Java GC:为什么两个幸存者区域?

shr*_*000 72 java garbage-collection jvm

对于Sun/Oracle的JVM,我读过GC algo将新一代划分为一个Eden区域和两个幸存区域.我想知道的是,为什么两个幸存者地区而不仅仅是一个?算法可以在伊甸园和一个幸存者区域之间保持乒乓(目前两个幸存者区域之间的方式); 或者这种方法有什么缺点吗?

Rya*_*art 72

我相信JRockit的GC实现更像你的建议,只有一个伊甸园和单个幸存者空间,但不要引用我.

HotSpot JVM的两个幸存者空间的原因是减少了处理碎片的需要.新对象在eden空间中分配.一切都很好.当它已满时,你需要一个GC,所以杀死过时的对象并将活动对象移动到幸存者空间,在升级到老一代之前,它们可以成熟一段时间.到目前为止仍然很好.但是,下次我们用完伊甸园空间时,我们就有了一个难题.下一个GC出现并清除了伊甸园和幸存者空间中的一些空间,但这些空间并不是连续的.所以它更好

  1. 试着让伊甸园的幸存者进入幸存者空间中被GC清除的洞?
  2. 将幸存者空间中的所有对象向下移动以消除碎片,然后将幸存者移入其中?
  3. 只需说"拧它,我们无论如何都要移动所有东西",并将所有幸存者从两个空间复制到一个完全独立的空间 - 第二个幸存者空间 - 从而留下一个干净的伊甸园和幸存者空间,你可以在下一个GC重复序列?

Sun对这个问题的回答很明显.

  • 我觉得这个答案不正确 - 你所描述的复制算法是不正确的.复制GC将所有对象从"从"空间复制到"到"空间.之后,两个空格都会切换角色.也就是说,新对象的分配将始终发生在"from"空间中(而"to"空间始终为空),因此不存在碎片问题.更好的解释是使用3个空格以更有效的方式利用内存,如下所述:http://stackoverflow.com/questions/21476348/java-gc-why-two-survivor-spaces (10认同)
  • 这对我来说并不明显.HotSpot JVM有哪些替代方案? (3认同)
  • @ vz0:这是第3个选项. (3认同)
  • @维卡什。这基本上意味着 GC 将遵循标记、清除和压缩规则来克服碎片。在压缩阶段,所有活动对象都移向幸存者内存的起始位置,删除幸存者内存之间的非活动对象。 (2认同)

Nee*_*ngh 21

在小型垃圾收集操作之后,两个幸存者空间的角色会被颠倒

两个幸存者空间.这些对象保留了至少一个小的垃圾收集幸存的对象,但在升级到老一代之前又被给予了另一个无法访问的机会.其中只有一个持有对象,而另一个大部分时间未使用.

在小型垃圾收集的操作期间,将标记已被发现为垃圾的对象.在集合中存活的伊甸园中的活物体被复制到未使用的幸存者空间.正在使用的幸存者空间中的活物体将被给予另一个在年轻一代中被回收的机会,也被复制到未使用的幸存者空间.最后,正在使用的幸存者空间中被认为"足够老"的活物体被提升为老一代.

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

资料来源:以上是Charlie Hunt和Binu John撰写的Java Performance第83页的摘录.


Pre*_*raj 5

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

Eden空间:新的对象将在内存池中分配。假设大多数对象在创建后不久就会被解除引用并变得无法访问。未取消引用的对象将被新一代垃圾收集器复制到幸存者空间中。在某些特殊情况下,它们可能会被直接复制到老一代池中。

幸存者空间:这两个小空间保存年轻代垃圾收集中幸存的对象。幸存的对象将从一个幸存者复制到另一个幸存者中(少量)次。这允许收获更多取消引用的对象。

老年代:最大的内存池,应该保存长寿命的对象。一旦对象离开幸存者空间,它们就会被复制到该池中。

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

其他优点:

  • 内存碎片
  • 提高 GC 性能

请找到以下链接了解更多详细信息,这可以帮助您了解更多

http://www.scalingbits.com/javaprimer

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