Luga Lee
作者Luga Lee·2023-07-24 10:23
系统架构师·None

一文读懂 Garbage Collection 与 CPU 资源

字数 4840阅读 502评论 0赞 2

Hello folks,我是 Luga,今天我们来聊一下 Java 虚拟机生态核心技术—— GC 技术,即 “Garbage Collection” 。

[注]:此 GC 非彼 GC 。

什么是 Garbage Collection ?

在计算机科学体系中,垃圾收集(GC)是一种自动内存管理的形式。垃圾收集器,也称为收集器,会尝试回收程序不再使用的对象所占用的内存空间。由于对象是使用 new 运算符动态分配的,因此程序员需要确保这些对象在不再使用时被销毁并释放内存,以便将内存用于以后的重新分配。

众所周知,在诸如 C 和 C++ 等语言中,我们需要手动管理对象的创建和销毁。然而,由于能力等各种原因可能会忘记销毁不再使用的对象,分配给它们的内存就没有被释放。这会导致系统的已用内存不断增长,最终可能导致系统中没有足够的内存可用于分配新的对象。这种情况被称为“内存泄漏”。

为了避免出现内存泄漏,我们需要使用 C 和 C++ 中的 free() 函数或者使用 delete() 方法释放已经不再使用的对象的内存。但在 Java 中,垃圾收集是自动进行的,我们无需手动释放内存,这就避免了内存泄漏的问题。

Java 的垃圾收集是程序在执行过程中自动进行的内存管理过程。Java 程序被编译成可以在 Java 虚拟机 (JVM) 上运行的字节码。在运行过程中,Java 对象被创建在堆中,这是专门为程序分配内存的一部分。因此,我们无需手动分配和释放内存,Java 虚拟机会自动回收不再使用的对象所占用的内存。

Garbage Collection 对性能的影响 ?

通常来讲,垃圾收集器的性能是由存活对象的数量而非死亡对象的数量决定的。 当垃圾收集器检测到越多的存活对象时,垃圾收集的速度就越慢,因为垃圾收集器必须花费更多的时间来识别和标记这些存活对象。 此外,垃圾收集器需要暂停应用程序的执行,以确保对象图的完整性。 发现的存活对象越多,暂停的时间就越长,这对应用程序的响应时间和吞吐量产生直接的影响。

这种垃圾收集暂停或 GC 暂停时间是分析垃圾收集对应用程序性能影响的基本原则。在具有多个线程的应用程序中,这种暂停时间很容易导致可伸缩性问题,因为暂停会阻塞所有线程的执行,从而影响应用程序的吞吐量和响应时间。

为了解决这个问题,垃圾收集器需要使用一些技术来减少暂停时间。例如,增量垃圾收集器可以将垃圾收集的过程分成多个阶段,在每个阶段之间允许应用程序继续执行。另外,分代垃圾收集器将堆分成多个代,每个代使用不同的垃圾收集策略,以提高垃圾收集的效率。这些技术可以帮助减少垃圾收集暂停时间,提高应用程序的可伸缩性和性能。

(来源:https ://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html )

从上述图表可以看出,随着 CPU 数量的增加,垃圾收集暂停仍然对应用程序的性能产生重要的影响。

这也表明了垃圾收集暂停对多线程应用程序吞吐量的影响。在拥有 32 个处理器的系统上,如果将 1% 的执行时间用于垃圾收集,那么应用程序将损失超过 20% 的吞吐量。如果将垃圾收集时间再增加到 2%,则总体吞吐量将再次下降 20%。这凸显出同时挂起 32 个执行线程的影响。

因此,在设计多线程应用程序时,需要考虑垃圾收集的影响,并选择适当的垃圾收集算法和配置参数以满足应用程序的需求。此外,为了减少垃圾收集暂停时间,可以采用一些技术,例如将堆分成多个代、使用增量垃圾收集器等。这些技术可以帮助提高应用程序的可伸缩性和性能,并减少垃圾收集对应用程序的影响。

如何观测 Garbage Collection 引起的CPU 资源消耗情况?

在现在的编程语言体系中,自动垃圾收集几乎是现代编程语言中的一项基础功能,例如 Golang、Node.js、Java、.NET 和 Python。虽然它通过自动删除未引用的对象为开发人员提供了便利,但在某些情况下它也可能导致 CPU 消耗过多。

当应用程序不断创建大量对象时,垃圾收集器会在后台持续运行以回收这些对象,从而消耗大量的 CPU 时间片。然而,对于许多开发人员来说,要准确地测量由于自动垃圾收集而消耗的 CPU 时间片可能具有挑战性。

这里,笔者介绍几种在实际的项目活动中所采用的常见策略,以供参考:

1、GC Log

第一个,肯定是当之无愧排名第一的大杀器—GC Log。GC Log 是了解垃圾收集器行为和其对系统性能的影响的宝贵资源。通过分析 GC Log,我们可以深入了解垃圾收集器的CPU 消耗情况。

GC Log 中通常包含实时、用户时间和系统时间等测量值,这些值反映了垃圾收集器完成收集过程所需的时间。实时表示垃圾收集事件的实际持续时间,而用户时间和系统时间分别代表垃圾收集期间用户级和系统级操作所消耗的 CPU 时间。

要确定垃圾收集所消耗的总 CPU 时间,可以计算 GC Log 中记录的用户时间和系统时间之和。该指标提供了对应用程序中垃圾收集器对 CPU 影响的估计。因此,GC Log 是优化应用程序性能的重要工具之一,需要及时记录和分析。

2、Dump 工具

如果我们想更详细地了解垃圾收集期间的 CPU 消耗,可以使用一些故障排除工具,例如 各种 Dump 工具。这些工具提供有关线程级别 CPU 消耗的详细信息,包括各个 GC 线程。

通过分析这些线程的 CPU 消耗情况,我们可以识别哪些 GC 线程正在占用大量 CPU 资源。这些信息可以帮助我们了解垃圾收集过程中 CPU 消耗的分布情况,并识别任何潜在的瓶颈或需要优化的区域。有了这些知识,我们就可以微调垃圾收集配置或探索替代垃圾收集算法以减少 CPU 消耗。

除了使用故障排除工具外,还有其他一些方法可以减少垃圾收集期间的 CPU 消耗。例如,可以使用对象池来重用对象,从而减少对象的创建和销毁次数。另外,可以使用分代垃圾收集器来优化垃圾收集过程,以便更有效地回收对象。

3、基础监控工具

监控工具提供了更广泛的视角,允许我们测量应用程序的整体 CPU 影响,包括垃圾收集。例如,“top” 等监控工具提供了一种整体方法来测量应用程序中的 CPU 消耗,从而深入了解整体 CPU 使用情况,包括垃圾收集的影响。

通过使用这些工具,我们可以评估总 CPU 消耗并确定由垃圾收集引起的特定 CPU 使用率。通过遵循这种方法,我们将全面了解应用程序中的 CPU 影响,包括垃圾收集和其他进程。同时,“top”等监控工具提供了更广泛的 CPU 使用情况视图,并帮助我们评估优化在降低总体 CPU 消耗方面的有效性。

需要注意的是,虽然监控工具可以提供有价值的见解,但将它们与其他方法(如 GC Log 分析)相结合可以增强我们对垃圾收集引起的特定 CPU 消耗的理解。例如,在 Java 中,我们可以使用 JConsole 或 JVisualVM 监视垃圾收集的行为,并结合使用“top”等监控工具来评估应用程序的总体 CPU 使用情况。

总之,了解垃圾收集期间的 CPU 消耗对于优化应用程序的性能和资源利用至关重要。 通过使用故障排除工具和采取其他优化措施,开发人员可以最大限度地减少垃圾收集对应用程序性能的影响。

降低 Garbage CollectionCPU 资源消耗的常见策略

基于前面的相关介绍和实践经验总结,实际上,在普通的业务场景中,采取措施降低垃圾收集的 CPU 资源消耗并不是难以解决的问题。这是因为有一些最佳实践可以遵循,具体如下:

1、调整堆内存

调整堆大小会对垃圾收集引起的 CPU 消耗产生重大影响。不适当的堆大小可能会导致频繁的垃圾收集周期或更长的收集时间,从而导致 CPU 利用率增加。

为了优化堆大小,考虑以下策略:

(1)增加堆大小:如果我们的应用程序经常遇到垃圾收集暂停或 CPU 使用率较高的情况,则增加堆大小会有所帮助。更大的堆允许在触发垃圾收集之前将更多对象留在内存中,从而减少收集周期的频率。

(2)减少堆大小:相反,如果我们的应用程序的内存占用量较低且垃圾收集周期不频繁,则减少堆大小可能会有所帮助。较小的堆需要较少的垃圾收集时间,从而降低 CPU 消耗。

(3)使用堆人体工程学:一些 JVM 提供自动堆大小调整算法,称为堆人体工程学。这些算法根据应用程序的行为动态调整堆大小。尝试启用堆人体工程学,以允许 JVM 自动优化堆大小。

建议逐步调整堆大小并监视对垃圾收集行为和 CPU 利用率的影响。找到最适合我们的应用程序内存需求并最大限度降低 CPU 消耗的平衡点。同时,需要注意的是,堆大小的调整应该根据具体的应用场景进行,而不是盲目地增加或减少堆大小。

2、调整 GC 策略

另一个有价值的策略是评估我们选择的编程语言中可用的不同垃圾收集 (GC) 算法并在其之间进行切换,以减少自动垃圾收集引起的 CPU 消耗。例如,在 Java(openJDK)中,有六种主要的 GC 算法:Serial、Parallel、Concurrent Mark & Sweep、G1、Z GC 和 Shenandoah。

每个 GC 算法都有自己的性能特征,包括 CPU 消耗和暂停时间,具体取决于应用程序的工作负载。通过进行彻底的分析并了解应用程序的具体要求,我们可以确定替代的 GC 算法,该算法可以显着降低 CPU 消耗。为了更好地了解每种 GC 算法的 CPU 消耗,请参考相关案例研究。

通过切换到更合适的 GC 算法,我们可以潜在地减轻 CPU 资源的负担并提高整体应用程序性能。需要注意的是,选择正确的 GC 算法需要综合考虑应用程序的内存需求、工作负载特征和系统硬件条件等多个因素,因此需要仔细分析和评估。同时,需要注意随着系统环境和应用程序的变化,GC 算法的最优选择可能会发生变化,因此需要定期评估和调整。

3、翻业务代码

在我们的业务逻辑实现过程中,有一些措施可以采取来降低 Garbage Collection(垃圾回收)引起的 CPU 资源消耗:

(1)对象池重用:通过使用对象池,可以重复使用已经创建的对象,减少对象的创建和销毁次数,从而减轻垃圾回收器的压力,降低 CPU 资源消耗。

(2)避免过多对象分配:在编写代码时,应尽量避免过多地分配对象。可以使用基本数据类型、静态变量、final 变量等来避免过多的对象分配,从而降低垃圾回收的频率和 CPU 资源消耗。

(3)分离对象和元数据:将对象和元数据分离存储,可以减少垃圾回收器扫描的元数据量,从而降低 CPU 资源消耗。

(4)延迟对象初始化:在对象不是立即需要的情况下,可以延迟其初始化。这样可以避免在创建对象时产生不必要的垃圾,减少垃圾回收的频率和 CPU 资源消耗。

(5)优化数据结构和算法:优化数据结构和算法可以提高代码的效率,减少对象的创建和销毁次数,从而降低垃圾回收的频率和 CPU 资源消耗。

综上所述,通过采取这些措施,可以降低 Garbage Collection(垃圾回收)引起的 CPU 资源消耗,提高应用程序的性能和资源利用率。需要注意的是,这些措施需要根据具体的业务场景进行选择和应用,以达到最佳的降低 CPU 资源消耗的效果。

由于 Garbage Collection(垃圾回收)技术涉及的面比较广,况且,基于不同的业务场景实现, 具体的实现和优化策略需要根据具体的业务场景和应用程序需求进行选择和应用。 在实际的业务场景中,我们需要进行 深入的分析和评估,确定最适合的垃圾回收方案和优化策略,以提高应用程序的性能和资源利用率。

同时,由于垃圾回收技术的复杂性和多样性,我们建议开发人员和系统管理员要不断学习和更新相关知识,了解最新的垃圾回收技术和优化策略,并将其应用到实际的业务场景中,以保持应用程序的高性能和稳定性。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

2

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广