Java, Go, Python语言的垃圾回收是怎么工作的?
垃圾回收是编程语言中的一种自动内存管理功能,用于回收程序不再使用的内存。它有助于防止内存泄漏并优化系统内存的使用。
垃圾回收器会识别程序无法再访问或不再需要的对象,并释放它们占用的内存。
01 Java
Java 提供多种垃圾回收器,每种回收器都适用于不同的使用情况。
-
串行 GC:
-
最适合单线程环境或小型应用程序。 -
使用单线程执行所有垃圾收集工作。
-
并行 GC:
-
也称为 "吞吐量收集器"。 -
使用多个线程进行垃圾收集,优化应用程序的最大吞吐量。
-
CMS GC:
-
低延迟收集器,旨在尽量减少暂停时间。 -
与应用程序同时工作,以减少暂停时间。
-
G1 GC:
-
旨在平衡吞吐量和延迟。 -
它将堆划分为若干区域,重点先收集垃圾最多的区域。
-
ZGC:
-
一种低延迟的垃圾收集器,专为需要大堆大小和最少暂停时间的应用而设计。 -
与应用程序线程同时运行。
02 Python
Python 的垃圾回收基于引用计数和循环垃圾回收器。
-
引用计数:
-
Python 内存管理的主要方法。 -
每个对象都有一个引用计数;当引用计数为零时,内存被释放。
-
循环垃圾回收器:
-
处理引用计数无法解决的循环引用。 -
Python 的 gc 模块提供了与垃圾收集器交互的工具,包括启用/禁用收集和调整阈值的函数。
03 GoLang
Go 使用的并发垃圾回收器随着时间的推移有了很大的发展:
-
CMS 垃圾收集器(Concurrent Mark-and-Sweep Garbage Collector):Go 的垃圾收集器与应用程序同时运行,最大限度地减少了 "世界停顿"(stop-the-world)。它标记活对象,清扫死对象,回收内存。
04 差异和性能目标
-
Java
-
多种 GC 算法:Java 提供多种垃圾回收器,如串行、并行、CMS、G1 和 ZGC,允许开发人员根据应用需求(吞吐量、延迟、内存占用)进行选择。 -
代际垃圾收集:Java 通常使用代际垃圾收集,将对象分为年轻一代和老一代,以优化收集过程。在年轻一代中多次收集后存活下来的对象会被转移到老一代中。 -
调整和配置:Java 为垃圾收集提供了大量调整选项,包括调整堆大小、启用/禁用特定收集器以及设置暂停时间目标。 -
灵活性和定制:Java 的多个垃圾收集器允许进行广泛的定制,以满足不同的性能目标,如最大化吞吐量或最小化延迟。 -
暂停时间控制:Java 提供了控制暂停时间(Pause Time)的机制,使其适用于有实时性要求的应用程序。
-
Python
-
引用计数:Python 主要使用引用计数进行内存管理。每个对象都会对指向它的引用进行计数;当计数降为零时,对象就会被去分配。 -
循环 GC:Python 有一个辅助垃圾回收机制,用于检测和回收循环引用(对象之间相互引用,但无法从根集访问)。gc 模块允许对循环垃圾回收器进行微调。 -
没有代际 GC:虽然 Python 确实有一个循环收集器,但它并没有像 Java 那样明确地使用代际方法。 -
简单易用:Python 将简单和易用放在首位。引用计数和循环 GC 的结合为开发人员提供了一个简单明了的模型,尽管对微调的控制较少。 -
开销:引用计数机制会增加一些开销,而且循环垃圾收集器的效率可能不如其他语言的生成收集器。
-
Go
-
并发标记和扫描:Go 使用并发标记和清扫垃圾收集器,该收集器与应用程序代码同时运行,旨在最大限度地减少停顿时间,降低延迟。 -
无世代垃圾回收器:Go 不会将对象分成不同的世代。重点在于保持低延迟和可预测的性能。 -
自动调整:Go 的垃圾回收器会根据应用程序行为自动调整,与 Java 相比,手动调整选项非常有限。 -
低延迟:Go 的垃圾回收器专为低延迟应用而设计。它最大限度地减少了 "世界停顿"(stop-the-world)的停顿时间,力求做到不引人注目。 -
并发性:Go 的垃圾回收器与应用程序同时运行,因此非常适合高吞吐量、低延迟的应用程序,尤其是在网络或云环境中。
总之,Java、Python 和 Go 中的垃圾回收机制是根据每种语言的特定目标和特点量身定制的。Java 提供了广泛的自定义功能和多种垃圾回收算法,Python 则将引用计数和循环垃圾回收相结合,以简化为优先考虑,而 Go 则侧重于低延迟、并发的垃圾回收,尽量减少开发人员的干预。
文章来源于ByteByteGo ,作者李华
THE END