【问题标题】:Why is heap divided into Eden, Survivor spaces and Old Generation?为什么堆分为伊甸园、幸存者空间和老年代?
【发布时间】:2018-05-10 06:58:52
【问题描述】:

你能回答我一个关于 JVM 垃圾收集过程的问题吗?

为什么堆分为伊甸园、幸存者空间和老年代?

在处理年轻疏散时,通过从根开始的引用访问对象以找出无法访问的对象。可达对象被标记为“活动”,不可达对象不被标记,将被淘汰。

因此,考虑 ALL 个对象,包括在老年代分配的对象,如果它们可达,也会被访问和标记。

据我了解,一次回收年轻代和老一代要求很高,因为这些代位于内存的不同连续部分。

但是,即使在 Young 疏散级别上进行了最简单的标记之后,如果所有可到达和不可到达的对象都已知并且可以删除,那么为什么我们需要这种划分?

我也知道弱代际假设,但为什么我们需要分裂?

【问题讨论】:

    标签: java garbage-collection jvm heap-memory g1gc


    【解决方案1】:

    基本前提是,当创建新对象时,不存在从旧对象到新对象的引用,并且对于很多对象,甚至大多数对象,这永远不会改变。这意味着,如果您可以证明仍然没有从旧对象到新对象的引用,或者当您确切知道创建了哪些引用时,您可以只对年轻代进行“次要”垃圾回收。

    这意味着必须跟踪和记住对旧对象的引用更改(但请记住此类更改不会经常发生的前提)。

    一种实施策略是Card Marking

    如果垃圾收集器没有收集整个堆(增量收集),则垃圾收集器需要知道从堆的未收集部分到堆的部分的指针在哪里正在收集。这通常用于分代垃圾收集器,其中堆的未收集部分通常是老年代,而堆中已收集的部分是年轻代。保存这些信息的数据结构(指向年轻代对象的老年代指针)是一个记忆集卡片表是一种特殊类型的记忆集。 Java HotSpot VM 使用字节数组作为卡片表。每个字节被称为一个卡片。一张卡片对应于堆中的一系列地址。 Dirtying a card 表示将字节的值更改为 dirty 值;脏值可能包含卡覆盖的地址范围内从老年代到年轻代的新指针。

    处理卡片意味着查看卡片以查看是否有老年代到年轻代的指针,并可能对这些信息做一些事情,例如将其转移到另一个数据结构。

    当然,使用生成只提供一个好处,如果它使我们能够在扫描期间跳过某些内存区域并且维护这些记忆集不会超过节省的成本。

    【讨论】:

    • 感谢您的回答!您能否详细解释一下“仅扫描年轻一代”的工作原理?)
    • @PavelPavel 表示扫描堆的一部分 - 堆的小得多的部分,因为它很小,扫描和回收内存只需要很少的时间
    • 我想,只是从某些 gc 根开始(扫描局部变量,但不扫描 static 字段),而不遍历任何指向老年代的引用。
    • @Holger 谢谢!我找不到任何关于在次要集合中扫描的分步教程
    • 这并不奇怪。大多数在线资源仅试图提供总体情况,而不是“分步教程”,因为您不应该成为垃圾收集器,甚至不应该自己实现垃圾收集器……顺便说一句,您的问题也是当我第一次听说“次要收藏”时,我的第一个问题。鉴于垃圾收集器跟踪实时引用而不是垃圾,这听起来很矛盾。只有在了解了记住的集合并且在这种设置中更改旧对象成为受监控的操作之后,它才有意义。
    【解决方案2】:

    如果您考虑 移动 收集器,则该除法非常有用。如果没有分离,年轻的集合会在堆中留下很多洞,需要空闲列表管理或旧代的压缩。

    另一方面,如果年轻代被实现为半空间 GC,则不需要此类清理和跟踪,因为根据定义,在次要收集之后,被疏散的空间将仅包含死对象,因此之后可以被视为空闲空间。这也支持在年轻代中分配凹凸指针。

    【讨论】:

      猜你喜欢
      • 2013-10-24
      • 1970-01-01
      • 2012-08-11
      • 1970-01-01
      • 2015-01-23
      • 1970-01-01
      • 2012-03-06
      • 1970-01-01
      • 2012-08-03
      相关资源
      最近更新 更多