83

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

4

7 回答 7

85

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

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

  1. 尝试将来自伊甸园的幸存者放入被 GC 清除的幸存者空间中的孔中?
  2. 将幸存者空间中的所有物体向下移动以消除碎片,然后将幸存者移入其中?
  3. 只需说“去他妈的,无论如何我们都在移动所有东西”,然后将两个空间中的所有幸存者复制到一个完全独立的空间——第二个幸存者空间——从而为你留下一个干净的伊甸园和幸存者空间,在那里你可以在下一个 GC 上重复序列?

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

于 2012-05-22T03:37:34.763 回答
25

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

两个幸存者空间。这些保存的对象至少在一次次要垃圾回收中幸存下来,但在被提升到老年代之前又被赋予了另一个机会变得不可访问。其中只有一个持有对象,而另一个大部分时间未使用。

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

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

来源:以上是Charlie Hunt 和 Binu John的Java Performance第 83 页的节选。

于 2013-01-16T16:11:45.047 回答
4

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

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

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

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

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

其他优点:

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

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

http://www.scalingbits.com/javaprimer

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

于 2014-09-16T14:39:57.363 回答
2

当前所有的答案都在谈论内存碎片,这也是在 GC 中产生世代的另一个原因。

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

多年来发现,只有“新”和“旧”是不够的,有一个“中年”的第三代就好了。

于 2014-09-27T11:13:56.480 回答
1

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

于 2012-05-28T21:49:18.873 回答
0

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

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

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

1.在young space,有Eden space for new Object,有两个Survivor Spaces(from和to),这两个Survivor Spaces的大小总是一样的。

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

3.如果Eden空间满了,GC就会运行,如果这个Eden空间里有任何对象,就会被移到Survivor Space。

4.在young space中,GC一般使用Copying Algorithm,速度快,每次都将survivor Objects复制到Survivor Space中的一个。

5.如果Survivor Space满了,剩下的live Objects直接复制到Old space。

6.在Old space,GC一般使用Mark-Compact算法,速度慢但占用内存少。

7.当旧空间变满时,垃圾会在那里收集,一个称为旧收集的过程。在旧空间中,长寿命的对象会停留在那里。

8.Out of Memory会发生新对象没有空间,即使对OLD或Perm部分进行了GC。

9.垃圾收集期间对象被移动:伊甸园->幸存者->终身(旧空间)

于 2018-03-13T19:17:18.453 回答
0

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

在此处输入图像描述

于 2017-11-21T10:28:27.863 回答