【问题标题】:how the live objects are figured out in young generation collection?如何在年轻代集合中找出活动对象?
【发布时间】:2011-04-20 09:57:21
【问题描述】:

我了解 YGC 所花费的时间与 Eden 中活动对象的数量成正比。我也了解如何在主要集合中找出活动对象(线程堆栈中的所有对象和静态对象以及可从这些对象传递的其他对象。)

但我不明白年轻代集合中的活动对象是如何计算出来的? 如果它解析线程堆栈,那么它需要解析 eden +tenured 空间,我认为情况并非如此。那么 JVM 是如何在 eden 中找到活动对象并将它们复制到 To Survivor 空间中的呢?

【问题讨论】:

    标签: java garbage-collection heap-memory


    【解决方案1】:

    我在这里引用article by Brian Goetz的相关文字。

    跟踪垃圾收集器,例如 复制、标记扫描和标记压缩, 都从根集开始扫描, 遍历对象之间的引用, 直到所有活体都被 参观了。世代追踪 收集器从根集开始, 但不遍历引用 导致对象在旧 代,从而减小了 要跟踪的对象图。

    【讨论】:

      【解决方案2】:

      为了只跟踪最年轻的一代,垃圾收集器会扫描相同的根集(堆栈和寄存器),并且还会扫描自上一次年轻代扫描以来已修改的所有较旧的(未收集的)代。只有那些被修改过的对象才有可能指向年轻代对象,因为未修改的对象不可能指向上次修改后创建的对象。

      所以棘手的部分是,GC 如何知道自上次 GC 以来哪些对象已被修改?有许多技术可以使用,但它们基本上归结为跟踪对老一代对象的写入。这可以通过捕获写入(写入屏障)或仅跟踪所有写入目标(写入缓冲区、卡标记)来完成,所有这些都会在 GC 未运行时增加程序执行的开销(因此它不会显示为 GC 暂停时间,但确实显示在总经过时间中)。硬件支持有很大帮助(如果有的话)。跟踪不需要精确,只要扫描每一个修改过的老一代对象(扫描未修改的对象是浪费时间,但不会伤害任何东西)。

      【讨论】:

        【解决方案3】:

        如何在年轻代集合中找出活跃对象?

        可以在 this article 中找到关于如何在 HotSpot 中实现分代收集的高级描述。

        一般来说,分代收集器将年轻代标记如下(假设我们只有两代):

        1. 它标记年轻对象并从线程堆栈帧和静态帧开始跟踪引用。当它找到对老一代对象的引用时,它会忽略它。
        2. 然后它重复该过程以在老年代中引用年轻代对象的引用。棘手的一点是在老年代识别这些引用而不标记整个老年代。
        3. 现在我们已经标记了新一代中所有可访问的对象......并且(该一代中的)其余对象都可以回收。

        在 HotSpot 中,包含年轻代引用的老年代对象使用“卡片表”来标识。老年代被划分为512字节的区域,每个区域都有一张“卡片”。如果该区域包含任何旧 -> 新生成指针,则设置卡中的位。然后在新一代收集期间跟踪设置了 Card 位的区域中的对象。

        棘手的事情是维护 Card 表,因为新的空间引用被写入旧代对象。在 HotSpot 中,这是使用软件写屏障来实现的,每当一个新的空间引用被写入对应于 Card 的内存区域时,它就会设置适当的 Card 的脏位。正如链接文章所指出的那样,这使得在对象中设置引用字段的成本更高,但由于大部分时间只能收集新一代所节省的时间,这显然是值得的。

        【讨论】:

        • 一点技术更正:卡表无条件更新,无论新指针是否指向新生代。基本上,语义是一个脏标志。此外,即使卡表中的条目是一个完整字节,它也只包含一位信息。这是为了性能。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-30
        • 2012-11-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多