爪哇GC:为什么两个幸存者地区?
对于Sun / Oracle的JVM,我已经读过GCalgorithm将新一代划分为一个Eden地区和两个幸存者地区。 我想知道的是,为什么两个幸存者地区,而不是一个? algorithm可以在伊甸园和只有一个幸存者地区之间保持乒乓球(目前在两个幸存者地区之间的方式); 或者这种方法有什么缺点?
我相信JRockit的GC实现更像你的build议,只有一个单一的伊甸园和单一的幸存者空间,但不要引用我的话。
HotSpot JVM的两个幸存者空间的原因是为了减less处理碎片的需要。 新的对象分配在伊甸园空间。 一切顺利。 当它满了,你需要一个GC,所以杀死陈旧的东西,把活的东西移到一个幸存者的空间,在那里他们可以成熟一段时间,然后被提升到老一代。 迄今为止还是不错的。 但是,下一次我们用尽了伊甸园的空间,我们有一个难题。 接下来的GC会出现并清除伊甸园和我们的幸存者空间中的一些空间,但空间不是连续的。 所以,它是更好的
- 试着将伊甸园的幸存者安置在幸存者空间的空洞中,并通过GC清除?
- 移动幸存者空间中的所有对象以消除碎片, 然后将幸存者移入其中?
- 只要说“拧紧它,我们就把所有东西都移动了”,然后把这两个空间中的所有幸存者都复制到一个完全独立的空间 – 第二个幸存者空间 – 这样就给你留下了一个干净的伊甸园和幸存者空间,你可以在那里在下一个GC上重复序列?
Sun对这个问题的回答是显而易见的。
两个幸存者空间的angular色在小垃圾收集操作之后被逆转
两个幸存者的空间。 这些东西至less保存了一个小垃圾收集的对象,但在被提升到老一代之前又被赋予了一个无法到达的机会。 其中只有一个持有对象,而另一个则大部分时间未被使用。
在小垃圾收集的操作中,已经被发现是垃圾的对象将被标记。 伊甸园中存活的收集物被复制到未使用的幸存者空间。 幸存者空间中正在使用的活体,将被赋予另一个年轻一代回收的机会,也被复制到未使用的幸存者空间。 最后,被使用的幸存者空间中被认为“足够老”的活物被提升到老一代。
在小垃圾收集结束时,两个幸存者空间交换angular色。 伊甸园完全是空的; 只有一个幸存者空间正在使用; 老一代的入住率略有增长。 由于活动对象在其操作期间被复制,因此这种types的垃圾收集器被称为复制垃圾收集器。
资料来源:以上是查理·亨特(Charlie Hunt)和宾努·约翰(Binu John)撰写的“ Java性能”第83页的摘录。
年轻一代:短期居住的地方,分为两个空间:
Eden空间:新对象将被分配在内存池中。 这个假设是,大多数对象在被创build后不久就被取消引用并且变得无法访问。 对象不被解除引用将由新一代垃圾收集器复制到幸存者空间中。 他们可能会将一些特殊情况直接复制到老一代池中。
幸存者空间:这两个小空间保留了年轻一代垃圾收集的幸存对象。 存活的物体将被复制一次(小),从一个幸存者转移到另一个。 这允许我们收获更多的解除引用的对象。
老一代:最大的记忆池应该保持长寿命的物体。 一旦他们离开幸存者空间,对象就被复制到这个池中。
代码生成:这个相当不明的池保存所有类的信息。 大多数应用程序不需要任何关注。 它可能需要适应多个类的一些应用程序。 如果应用程序永久地加载和卸载类,它可能还需要一些关注。
其他优点:
- 内存碎片
- 它改善了GC的性能
请查找以下链接以获取更多详细信息,以帮助您了解更多信息
所有当前的答案都谈论内存碎片,这也是在GC中有几代人的另一个原因。
运行时logging指向“新对象”的所有“旧对象”,这是每次更新“指针”字段时完成的。 然后当一个“矿工”GC完成时,只有“新”对象需要扫描。
多年来,发现只有“新”“老”是不够的,第三代“中年”是好的。
将一代人的所有实例从一个空间复制到另一个空间的优点和缺点是什么,而将它们以内存地址顺序复制到一代空间的开始? 按顺序处理项目可能需要为每个项目添加额外的指针,但是将消除对“幸存者”空间之一的需要。