这是有关垃圾收集(GC)的系列文章中的第一篇。 我希望能够涵盖整个系列过程中的理论知识以及热点虚拟机中的所有主要收集器。 这篇文章仅说明什么是垃圾回收,以及不同回收器共有的元素。
我为什么要在乎?
您的Java虚拟机可以为您管理内存-这非常方便-但默认情况下可能未对它进行优化调整。 通过了解垃圾收集背后的一些理论,您可以更轻松地调整收集器。 一个普遍关心的问题是收集器的效率,也就是说,您的程序花了多少时间执行程序代码而不是收集垃圾。 另一个常见问题是应用程序暂停的时间长。
关于垃圾收集还有很多传闻和民间传说,因此更详细地了解算法确实有助于避免陷入常见的陷阱和陷阱。 此外,对于任何对如何应用和使用计算机科学原理感兴趣的人,JVM内部都是一件很棒的事情。
停止世界是什么意思?
您的程序(或GC-Speak中的mutator)将在运行时分配对象。 在某个时候,需要收集堆,并且热点中的所有收集器都会暂停您的应用程序。 “世界停止”一词用于表示所有增变器的线程都已暂停。
可以实现不需要暂停的垃圾回收器。 Azul已在其Zing虚拟机中实现了有效的不间断收集器。 我不会介绍它是如何工作的,但是如果您想了解更多信息,会有一张非常有趣的白皮书 。
年轻/弱世代假说
简而言之: 大多数分配的对象都死于年轻 1 。 通过对1980年代一大批程序的内存分配和活动模式进行实证分析,证明了这一概念。 研究人员发现,不仅大多数物体死于年轻,而且一旦它们活到一定年龄,它们就会活很长一段时间。 下图取自SUN / Oracle研究,以直方图的形式查看了对象的寿命。
堆的组织方式如何?
年轻的世代假设催生了世代垃圾收集的思想,在世代垃圾收集中,堆被分为几个区域,每个区域中对象的放置与它们的年龄相对应。 以上这些垃圾收集器( G1除外)共有的一个要素是将堆组织到不同空间的方式。
最初分配对象时(如果适合)将它们存储在Eden空间中。 如果对象在集合中幸存下来,那么它将最终到达幸存者空间。 如果它能够存活几次(您的使用期限阈值),则该对象最终将出现在使用期限的空间中。 收集器收集这些空间的算法的细节各不相同,因此我将在以后的博客文章中单独介绍它们。
这种划分是有益的,因为它允许您在不同的空间上使用不同的算法。 如果大多数对象都已失效,则某些GC算法效率更高;如果大多数对象都处于活动状态,则某些GC算法效率更高。 由于世代相传的假设,通常是到了在伊甸园收集大多数物体的时候,幸存者空间已经死了,而保有权的大多数物体还是活着的。
还有永久性的-永久的一代。 这是一个特殊的世代,其中包含与Java语言本身相关的对象。 例如,此处包含有关已加载类的信息。 从历史上看,被插入或为常量的字符串也保存在这里。 永久代已被删除,转而支持元空间 。
多个收藏家
热点虚拟机实际上具有各种不同的垃圾收集器。 每个都有不同的性能特征集合,并且更(或更少)适合于不同的任务。 我将要研究的关键垃圾收集器是:
- 并行清理 (PS):最近发布的JVM中的默认收集器。 为了收集而停止运行,但是并行收集(即使用多个线程)。
- 并发标记扫描 (CMS):此收集器具有多个阶段,其中一些阶段使世界停滞不前,但在该阶段的多个阶段也与程序同时运行。
- 增量并发标记扫描 (iCMS):CMS的一种变体,旨在降低暂停时间。 有时可以做到这一点!
- 垃圾优先 (G1):一种新型的收集器,最近变得更加稳定,并且使用量正在缓慢增加。
结论
我已经对垃圾收集提出了一些介绍性的观点,在下一篇文章中,我将介绍Parallel Scavenge收集器-它是当前的默认收集器。 我还想提供我的雇主链接,该雇主拥有我们认为非常有用的GC日志分析器 。
- “热点”是在openjdk和官方Oracle JVM之后通用的代码库的名称。 从Java 7开始,openjdk是Java SE的参考实现。
- 从技术上讲,我上面描述的是具有经验验证的“弱代假设”。 还有一个很强的变体,可以说是:堆分配对象的平均生存期等于可访问存储的平均数量 。 实际上,这可以通过采取利特尔定律并将Λ设置为1来从数学上证明。
- 我将在G1特定的博客文章中介绍G1中堆的组织方式。
翻译自: https://www.javacodegeeks.com/2013/06/garbage-collection-in-java-1.html