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


77

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


2
有趣-您介意将链接发布到您所读到的地方吗?我认为这将有助于解决这个问题。编辑: 这篇文章似乎在描述它,不确定是否与您阅读的相同。
保罗·贝洛拉

保罗·贝洛拉(Paul Bellora):并不是每个人都说这个链接,但我已经在多本书和多篇文章中阅读了。将很快发布这些链接。
shrini1000

@保罗Bellora这是Java 5,但它是从“survivior空间确实提到“到”和:oracle.com/technetwork/java/javase/...
shrini1000

太棒了,谢谢您的链接-还有一个很好的问题!
Paul Bellora 2012年

Answers:


79

我相信JRockit的GC实现更像您建议的那样工作,只有一个eden和一个幸存者空间,但请不要在此引用我。

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

  1. 尝试将幸存者从伊甸园中插入幸存空间中被GC清除的孔中吗?
  2. 向下移动幸存者空间中的所有对象以消除碎片,然后将幸存者移入其中?
  3. 只需说出“拧紧它,我们无论如何都会移动所有东西”,然后将两个空间中的所有幸存者都复制到一个完全独立的空间(第二个幸存者空间)中,从而为您提供一个干净的伊甸园和幸存者空间在下一个GC上重复该序列?

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


3
这对我来说并不明显。HotSpot JVM可以采用什么替代方案?
vz0 2012年

1
感谢您提供非常清晰准确的答案。如果可能的话,您也可以请。评论JRockit使用哪个选项?
shrini1000


10
我发现此答案不正确-您描述的复制算法不正确。复制GC将所有对象从“从”空间复制到“至”空间。此后,两个空格切换角色。也就是说,新对象的分配将始终在“ from”空间中进行(而“ to”空间始终为空),因此不会出现碎片问题。一个更好的解释是使用3个空格这里描述利用存储在一个更有效的方式:stackoverflow.com/questions/21476348/...
阿舍萨班

有人可以为选项二(2)提供帮助吗?“下降”是什么意思,整行在这里意味着什么。“向下移动幸存者空间中的所有对象以消除碎片”
Vikash

24

在进行次要垃圾收集操作后,两个幸存者空间的作用相反

两个幸存者空间。这些保存的对象至少可以进行一次较小的垃圾回收,但是在提升为老一代之前,又有另一种变得无法访问的机会。它们中只有一个保存对象,而大多数情况下则不使用其他对象。

在次要垃圾回收操作期间,将标记已发现为垃圾的对象。可以在集合中生存的伊甸园中的活动对象被复制到未使用的生存者空间。正在使用的幸存者空间中的活动对象,将被赋予在年轻一代中进行回收的另一次机会,也将复制到未使用的幸存者空间中。最后,幸存者空间中正在使用的被认为“足够老”的活动物体被提升为老一代。

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

资料来源:上面是Java Performance第83页的摘录,作者是Charlie Hunt和Binu John。


4

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

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

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

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

永久物生成:这个相当未知的池保留了所有类的信息。对于大多数应用程序,它不需要任何注意。可能需要将其修改为具有许多类的某些应用程序。如果应用程序永久加载和卸载类,则可能也需要注意。

其他优点:

  • 内存碎片
  • 改善GC性能

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

http://www.scalingbits.com/javaprimer

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


2

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

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

多年以来,已经发现仅拥有“新”和“旧”是不够的,拥有“中年”的第三代是很好的。


1

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



0

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

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

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

1.在年轻空间中,有一个伊甸园空间可以容纳新物体,并且有两个幸存者空间(从和到),这两个幸存者空间的大小始终相同。

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

3.如果Eden空间已满,GC将运行,如果该Eden空间中存在任何对象,则将这些对象移动到Survivor Space。

4.在年轻空间中,GC通常使用复制算法,该算法速度很快,每次将生存对象复制到其中一个生存空间中。

5.如果Survivor Space已满,则将其余活动对象直接复制到Old space。

6.在旧空间中,GC通常使用Mark-Compact算法,该算法速度较慢,但​​需要较少的内存。

7,当旧空间变成满垃圾时,将在其中收集一个称为旧集合的过程。

8,内存不足的情况将发生,即使为OLD或Perm部分完成GC也没有空间容纳新对象。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.