首页 > 解决方案 > 次要和主要 GC 周期

问题描述

AFAIK,Java GC 具有次要 GC(低成本)和主要 GC 周期(高成本)。如果对象在本地范围内,则在次要 GC 中对其进行清理。如果对象的引用存储在代码中的其他地方,那么它会在主要 GC 中被清除。
所以例如

void f() {
   A a = new A();
   a.doSomething();
}

根据我的描述(如果它当然是真的)对象 a 在次要 GC 中被清理。关于什么

void f() {
   A a = new A();
   B b = new B();
   b.doSomething(a);
}

这里对象 a 作为参数传递给 B 的 doSomething 方法,也许 B 将引用存储在 B 本身中,但我们不知道。在这种情况下,对象a会在minor GC还是major GC中被清除?

标签: javagarbage-collectionjvm

解决方案


您需要一些关于 GC 工作原理的基本假设的帮助。

我们假设您将 HotSpot 与 G1 一起使用,因为还有其他几种以不同方式工作的替代方案(例如我为之工作的 Azul 的 Zing 中的 C4)。

堆分为两个区域,称为年轻代和老年代。首次分配对象时,从 Eden 空间提供空间,该空间是年轻一代的一部分(有时大对象直接在老一代中分配。但让我们像您的示例一样保持简单)。Eden 空间中的分配使用简单的指针碰撞方法,这会导致非常快速的分配。

当当前分配指针到达可用内存范围的末尾时,会发生次要 GC。这会将对象复制到幸存者空间之间的幸存者空间,并将寿命较长的对象提升到老一代。然后分配指针被重置到伊甸园空间的开头,有效地免费收集所有垃圾。

老一代。是一个单独的内存逻辑区域,使用不同的算法来回收空间和消除碎片。这是一个主要的收藏。

何时发生这些集合不是由分配对象的位置来确定的,而是由 VM 决定何时需要收集来确定的。这将取决于 Eden 空间何时耗尽或旧代中的可用空间何时耗尽。低于某个阈值。

在您的第一个示例中,不能保证在次要 GC 期间会收集对象“a”。如果 doSomething() 需要很长时间并且有其他线程分配大量对象,则可能会发生几次次要 GC,并且“a”最终可能会被提升为旧代。(并作为主要 GC 的一部分收集)。

在您的第二个示例中,如果 doSomething() 快速返回并且没有在任何地方记录对“b”的引用,则“a”和“b”都可以作为次要 GC 的一部分被收集。


推荐阅读