MaxTenuringThreshold - 它是如何工作的?

43

我们知道有几个主要的内存域: Young(年轻代)、Tenured (Old gen,老年代)和 PermGen。

  • Young 域被划分为 Eden 和 Survivor (两个)。
  • OldGen 用于保存生存对象。

MaxTenuringThreshold 防止对象过早地被复制到 OldGen 空间。这一点相当清楚易懂。

但是它是如何工作的?垃圾回收器如何处理那些仍然存活到达 MaxTenuringThreshold 的对象,以及它们在哪里?

对象会被复制回 Survivor 空间进行垃圾回收…还是以其他方式进行?

2个回答

76

Java堆中的每个对象都有一个标头,垃圾回收(GC)算法使用该标头。年轻代空间收集器(负责对象晋升)使用该标头的几位来跟踪已经存活的对象的收集次数(32位JVM用于此4位,64位可能多一些)。

在年轻代空间收集期间,每个对象都会被复制。该对象可能被复制到其中一个幸存空间(在年轻代GC之前为空的空间)或老年代。对于正在被复制的每个对象,GC算法会增加它的年龄(已经存活的收集数),如果年龄超过当前的tenuring threshold,则会将其复制(晋升)到老年代。如果幸存空间已满(溢出),该对象也可以直接复制到老年代。

对象的运行方式如下:

  • 分配在eden区
  • 由于年轻代GC从eden区复制到survival space
  • 由于年轻代GC从survival space复制到(其他)survival space(这可能会发生几次)
  • 由于年轻代GC(或full GC)从survival space(或可能是eden区)晋升到老年代。

JVM实际上动态调整了tenuring threshold,但MaxTenuringThreshold设置了其上限。

如果将MaxTenuringThreshold = 0,则所有对象都会立即晋升。

我有一些关于java垃圾回收的文章,您可以在那里找到更多详细信息。


你没有回答改变MaxTenuringThreshold会如何影响GC。如果我将其设置为6?15?会有什么区别? - rustyx
MaxTenuringThreshold 的最大(有效)值在哪里有记录? - Michael
你不应该将值设置超过15。参考资料:https://support.oracle.com/knowledge/Middleware/1283267_1.html - Meghana Randad

18

(免责声明:此处仅涵盖HotSpot VM)

正如Alexey所说,实际使用的tenuring阈值是由JVM动态确定的。设置它的价值非常小。对于大多数应用程序来说,默认值15足够高了,因为通常有更多的对象在收集中幸存下来。 当许多对象幸存下来时,survivor空间直接溢出到old区。这被称为过早晋升,并且是问题的指标。然而,通过调整MaxTenuringThreshold很少能解决该问题。

在这些情况下,有时可能会使用SurvivorRatio来增加survivor空间的空间,从而使tenuring真正起作用。 然而,通常情况下,扩大young generation是唯一的好选择(从配置角度考虑)。 如果你从编码角度考虑,应避免过多地分配对象,让tenuring按设计工作。

确切回答您问的问题: 当一个对象达到其JVM确定的tenuring阈值时,它将被复制到old区。在此之前,它将被复制到空的survivor空间。已经存活一段时间但在达到阈值之前被解除引用的对象会被非常高效地从survivor中清除。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接