MaxTenuringThreshold - 它究竟是如何工作的?

2022-09-01 02:23:16

我们知道很少有主要的内存领域:Young,Tenured(Old Gen)和PermGen。

  • 年轻的领域分为伊甸园和幸存者(有两个)。
  • OldGen用于幸存的对象。

MaxTenuringThreshold可以防止对象过早地最终复制到OldGen空间。这是非常清楚和可以理解的。

但是它是如何工作的呢?垃圾收集器如何处理这些仍然存活到MaxTenuringThreshold的对象,以及以何种方式?它们位于何处?

对象被复制回幸存者空间以进行垃圾回收。还是以其他方式发生?


答案 1

Java 堆中的每个对象都有一个由垃圾回收 (GC) 算法使用的标头。年轻的空间收集器(负责对象升级)使用此标头中的几个位来跟踪幸存下来的集合对象的数量(32 位 JVM 为此使用 4 位,64 位可能更多)。

在年轻的空间收集期间,每个对象都会被复制。对象可以复制到生存空间之一(在年轻GC之前是空的)或旧空间。对于要复制的每个对象,GC 算法都会增加其期限(存活的集合数),如果期限高于当前的期限阈值,则会将其复制(提升)到旧空间。如果生存空间已满(溢出),也可以直接将对象复制到旧空间。

对象的旅程具有以下模式:

  • 在伊甸园中分配
  • 由于年轻的GC从伊甸园复制到生存空间
  • 由于年轻的GC而从生存复制到(其他)生存空间(这种情况可能会发生几次)
  • 由于年轻的GC(或完整的GC)而从生存(或可能的伊甸园)提升到旧空间

实际的张力阈值由JVM动态调整,但MaxTenuringThreshold为其设置了上限。

如果设置 MaxTenuringThreshold=0,则所有对象将立即升级。

有几篇关于java垃圾回收的文章,在那里你可以找到更多细节。


答案 2

(免责声明:这仅适用于 HotSpot VM)

正如Alexey所说,实际使用的张力阈值是由JVM动态确定的。设置它的价值很小。对于大多数应用程序,默认值 15 将足够高,因为通常集合中会有更多的对象存活下来。当许多物品在收藏中幸存下来时,幸存者的空间会直接溢出到旧空间。这被称为过早晋升,是问题的指标。然而,它很少可以通过调整MaxTenuringThreshold来解决。

在这些情况下,有时可以使用SurvivorRatio来增加幸存者空间中的空间,从而使Tenuring真正起作用。然而,大多数情况下,扩大年轻一代是唯一好的选择(从配置的角度来看)。如果从编码的角度来看,则应避免过多的对象分配,以使 Tenuring 按设计工作。

为了准确回答您的问题:当一个对象达到其JVM确定的保留阈值时,它将被复制到旧对象。在此之前,它将被复制到空的幸存者空间。已经存活了一段时间但在达到阈值之前被取消引用的对象将非常有效地从幸存者中清除。