了解GC G1 - 并发标记阶段

4

我正在尝试理解有关GC G1的一些内容,希望你们能帮助我。

  1. GC G1中整个并发标记阶段的作用是什么?我的意思是所有部分(初始标记,根区域扫描,...,清理)。

据我所知,它的作用是标记从根区域可达的所有活动对象(在并发标记阶段中,这些对象是在“初始标记”部分中选择的幸存者区域),并估计老区域的存活率(基于此,它们将被选择为混合疏散暂停的收集集)。我是对的吗?

  1. 在混合疏散暂停期间,哪些对象被标记为垃圾?

如果我理解正确,混合疏散暂停会标记和删除GC根和已记忆集无法访问的对象。这是与并发标记标记的不同对象,因此这些对象可能重叠但不必如此。我是对的吗?

  1. GC根到底是什么?它们在年轻代和混合收集时是否相同(除了混合收集中来自已记忆集的引用)?

  2. 下面是我的总结,是否正确?

完全年轻代收集标记所有活动对象(这意味着对于GC根是可达的)从伊甸园和幸存者区域,并将它们疏散(复制)到新的幸存者(或旧的)区域。其余的对象被视为垃圾并被删除。空闲区域被回收。

在并发标记阶段开始时,标记可能具有对老年代区域的引用的所有幸存者区域(基于已记忆集?)。在此过程中,幸存者区域被视为GC根,因为此部分发生在完全年轻代收集期间,因此我们确定其中所有对象都是活的。然后,GC遍历对象图(从所选的幸存者区域的对象开始),并标记所有活动对象。

在混合疏散暂停期间,根据存活率统计信息(在上一阶段中计算),选择某些老年代区域进入收集集。然后,从所选区域中的所有活动对象疏散(复制)到新区域(活动对象的意思是:a.在并发标记期间被选择和b.如在标准疏散暂停期间 - 可达GC根和已记忆集的对象)。其余的对象被视为垃圾,区域被回收。

1个回答

1
  1. GC G1中整个并发标记阶段的作用是什么?我的意思是所有部分(初始标记,根区域扫描,...,清理)。

标记阶段的作用是从根开始遍历所有连接的组件,并将其标记为“活动的”。

“并发”意味着这是在多个根上同时进行的。


  1. 在混合撤离暂停期间,哪些对象被标记为旧区域中的垃圾?

没有。

目标是仅标记活动对象。任何未标记为活动的对象都会自动(正确地)被认为是死亡的。


  1. GC根究竟是什么?它们在年轻代和混合收集中是否相同(除了混合收集中记忆集中的引用)?

本文链接到另一个SO问题,列出了以下四种GC根:

  1. 局部变量;
  2. 活动线程;
  3. 静态变量;以及
  4. JNI引用。

根的定义与集合集无关。根是任何GC代或集合中的根。


  1. 我的总结是否正确?

这是四个问题中最难回答的一个。请允许我跳过这个问题。 :)


我认为列出的GC根节点有点不准确。关于第一点 - 无论是本地变量还是方法参数,都被视为GC根节点,因为它们存在于活动线程的堆栈上。第四点仅适用于系统类加载器加载的类的静态字段(因为系统类加载器是GC根节点,所以它加载的所有类也是)。 - Nikita Tkachenko
@NikitaTkachenko:惊人的是,很难找到一个权威的答案来解释什么是GC根对象。我花了大约15分钟的时间搜索这个我认为非常基础的问题。然而,我找到的最好的答案在《Java性能优化第二版》这本书中... 这个答案没有列出根,但是告诉我们它们语义上是什么。那就是...(1/2) - displayName
这些对象可以从堆外访问。主要包括线程堆栈和系统类。这些对象始终是可达的,因此GC算法会扫描所有通过一个根对象可达的对象。通过GC根可达的对象是活动对象;其余不可达的对象是垃圾(即使它们保持对活动对象或彼此的引用)。 - displayName
3
@NikitaTkachenko 这取决于具体的实现。原则上,垃圾回收器可以通过在遇到声明类时考虑 static 变量来实现,因此不需要将任何静态变量视为GC根。然而,一些实现会采取捷径,仅针对引导加载程序、扩展/平台加载程序和应用程序(也称为系统加载器),因为它们永远不会消失;或者对于所有静态变量,如果它们不支持类卸载。关于第一个观点,方法参数 局部变量,同样适用于字节码级别的 this - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接