为什么是两个幸存者区域?

对于 Sun/Oracle 的 JVM,我了解到 GC 算法将新一代分为一个伊甸园区域和两个幸存者区域。我想知道的是,为什么是两个幸存者区域,而不是一个?算法可以在伊甸园和一个幸存者区域之间进行乒乓球游戏(就像目前在两个幸存者区域之间进行乒乓球游戏一样) ; 或者这种方法有什么缺点吗?

36648 次浏览

我相信 JRockit 的 GC 实现更像您建议的那样,只有一个伊甸园和一个幸存者空间,但不要引用我的话。

HotSpot JVM 有两个幸存者空间的原因是为了减少处理碎片的需要。在伊甸园空间中分配新对象。一切都很好。当它满了,您需要一个 GC,所以杀死陈旧的对象并将活的对象移动到幸存者空间,在那里它们可以成熟一段时间,然后再提升到老一代。目前为止还不错。下次我们用光了伊甸园的空间,我们就有难题了。下一个 GC 出现了,在 Eden 和我们的幸存者空间中清除了一些空间,但这些空间并不是连续的。所以最好

  1. 试着把伊甸园的幸存者塞进被 GC 清空的幸存者空间的洞里?
  2. 将幸存者空间中的所有物体向下移动以消除碎片,然后 那么将幸存者移入其中?
  3. 只要说“去他的,我们无论如何都要移动所有东西”,然后把两个空间的所有幸存者复制到一个完全独立的空间——第二个幸存者空间——这样就给你留下了一个干净的伊甸园和幸存者空间,你可以在下一个 GC 上重复这个序列?

Sun 对这个问题的回答是显而易见的。

将一代的所有实例从一个空间复制到另一个空间,相对于按照内存地址顺序复制到一代空间的开始,有哪些优点和缺点?按顺序处理项目可能需要为每个项目添加一个额外的指针,但是可以消除对“幸存者”空间之一的需要。

两个幸存者空间的角色在操作次要的垃圾收集之后发生逆转

两个幸存者空间。这些保存的对象至少经历了一次次要的垃圾收集,但是在提升到老一代之前又有机会变得无法访问。其中只有一个包含对象,而另一个大部分时间都包含对象 没用过。

在操作次要的垃圾收集期间,将标记已被发现为垃圾的对象。集合中幸存下来的伊甸园中的活对象被复制到未使用的幸存者空间。正在使用的幸存者空间中的活对象也被复制到未使用的幸存者空间中,这些活对象将在年轻一代中再次获得回收的机会。最后,使用中的幸存者空间中的活动对象被视为 “足够老”被提升到老一代。

在次要垃圾收集结束时,两个幸存者空间交换角色。伊甸园完全是空的; 只有一个幸存者的空间在使用; 老一代人的居住率略有增长。因为活动对象是在其操作期间复制的,所以这种类型的垃圾收集器称为复制垃圾收集器。

资料来源: 以上是由查理 · 亨特和比努 · 约翰撰写的 一个 href = “ https://rads.stackoverflow. com/amzn/click/com/B005R4NELQ”rel = “ noReferrer”rel = “ nofollow noReferrer”> Java 性能 第83页的节选。

年轻一代: 这是短暂居住的地方,分为两个空间:

伊甸园空间: 将在内存池中分配新对象。这里的假设是,大多数对象在创建后不久就会被取消引用并变得不可访问。未被取消引用的对象将被新一代垃圾回收器复制到幸存者空间中。在某些特殊情况下,它们可能会被直接复制到旧的生成池中。

存活空间: 这两个小空间保存年轻一代垃圾回收的存活对象。存活的对象将被从一个存活对象复制到另一个存活对象(少量)。这使得我们可以获得更多的去引用对象。

老一辈: 最大的内存池,应该保持长期的生活对象。对象一旦离开幸存者空间就会被复制到这个池中。

永久生成: 这个相当未知的池保存所有类的信息。对于大多数应用程序,它不需要任何关注。它可能需要适应一些具有许多类的应用程序。如果应用程序永久加载和卸载类,也可能需要注意。

其他优点:

  • 内存碎片
  • 它提高了 GC 性能

请参考以下连结了解更多资料

Http://www.scalingbits.com/javaprimer

Http://java.sys-con.com/node/84695

当前所有的答案都是关于内存碎片的,这也是 GC 中有代的另一个原因。

运行时记录所有指向“新对象”的“旧对象”,每次更新“指针”字段时都会这样做。然后,当一个“小”GC 完成时,只有“新”对象需要被扫描。

多年来,人们发现只有“新”和“老”是不够的,有第三代“中年”是好的。

两个幸存者是标记和拷贝算法的实现。这些在 GC 中用于年轻一代。正如 Ryan 在选项3 给你中提到的

enter image description here

Java 中的堆内存 在称为堆内存的区域中创建的 Java 对象。堆内存是在 JVM 启动时创建的,而堆内存是在 Java 应用程序运行时增加或减少的。当堆内存满时,垃圾收集器将删除未使用的对象,因此垃圾收集器将为新对象留出空间。

堆内存分为两个区域(或代) ,称为

1. 年轻空间。 2. 旧空间。

1.在年轻空间中,存在新对象的伊甸园空间和两个生存空间(从和到) ,这两个生存空间总是相同的大小。

2.生存空间用于存储生存对象。当年轻空间已满时,垃圾收集器通过运行一个特殊的年轻收集来删除未使用的对象,其中所有在年轻空间中生存了足够长时间的对象都被提升(移动)到旧空间,从而释放年轻空间以进行更多的对象分配。

3.如果伊甸园空间已满,GC 将运行,如果有任何对象活在这个伊甸园空间,这些将被移动到幸存者空间。

4.在年轻空间,GC 通常使用复制算法,这是快速的,每次,生存对象被复制到一个幸存者空间。

5. 如果幸存者空间已满,其余的活对象将直接复制到旧空间。

在旧的空间中,GC 通常使用标记-紧凑算法,这种算法速度较慢,但需要的内存较少。

7.当旧空间变成完全的垃圾时,一个叫做旧收集的过程就会被收集起来。

8. 内存不足将发生,新对象没有空间,甚至旧对象或 Perm 部分的 GC 也没有空间。

对象在垃圾收集期间被移动: eden-> 幸存者-> 保留期(旧空间)