为什么要让短期和长期存在的对象在垃圾回收中发挥作用?

2022-09-01 18:34:17

我经常读到,在Sun JVM中,短寿命对象(“相对较新的对象”)可以比长期存在的对象(“相对较旧的对象”)更有效地进行垃圾收集。

  • 为什么会这样?
  • 这是特定于 Sun JVM 的,还是由一般的垃圾回收原则引起的?

答案 1

大多数Java应用程序创建Java对象,然后相当快地丢弃它们。例如。你在一个方法中创建一些对象,然后一旦你退出该方法,所有对象都会死亡。大多数应用程序都以这种方式运行,大多数人倾向于以这种方式编写应用程序代码。Java堆大致分为3部分,永久的,旧的(长期的)代和年轻的(短暂的)一代。年轻的一代进一步分为S1,S2和伊甸园。这些只是堆。

大多数对象都是在年轻的一代中创建的。这里的想法是,由于物体的死亡率很高,我们快速创建它们,使用它们,然后丢弃它们。速度至关重要。当您创建对象时,年轻的一代会填满,直到发生次要的GC。在次要 GC 中,所有处于活动状态的对象都从 eden 复制过来,并显示 S2 到 S1。然后,“指针”位于伊甸园和S2上。

每个副本都会使对象老化。默认情况下,如果一个对象存活了 32 个副本,即 32 个次要 GC,则 GC 会显示它将存在更长时间。所以,它所做的就是通过把它搬到老一辈人身上来保持它。老一代只是一个大空间。当旧一代填满时,一个完整的GC或主要GC发生在旧一代中。由于没有其他空间可以复制到,因此必须压缩 GC。这比次要GC慢得多,这就是为什么我们避免更频繁地这样做。

您可以使用

java -XX:MaxTenuringThreshold=16 

如果你知道你有很多长寿的物体。您可以使用以下命令打印应用的各种年龄存储桶

java -XX:-PrintTenuringDistribution

答案 2

(请参阅上面对更一般的GC的解释..这回答了为什么新的GC比旧的更便宜)。

可以更快地清除伊甸园的原因很简单:该算法与伊甸园空间中GC中将在GC中存活的对象数量成正比,而不是与整个堆中的活动对象数量成正比。即:如果你在伊甸园中的平均对象死亡率为99%(即:99%的对象不能存活GC,这并不异常),你只需要查看并复制这1%。对于“旧”GC,需要标记/扫描整个堆中的所有活动对象。这要贵得多。