Java 内存中的 Survivor Space 有什么用?

What is the purpose of Survivor Space in Java memory?

试着查找这个,但我遇到的所有 questions/answers 都在谈论拥有 2 个幸存者 space 的目的。我想大致了解幸存者 space 的目的。将物体从 Eden 移动到 Survivor 有什么好处?

性能.

一般来说,拆分堆(分代或任何其他鉴别器)被视为一件相当好的事情,但并非所有收集器都遵循这一点(例如 Shenandoah 不是这样的收集器)。

为什么这是好事?扫描整个堆以查找存活 Objects 需要时间。你如何告诉你的垃圾收集器 - “现在 运行 的时间”。 那个时间是什么时候?你可以说:在每第 100 个分配 Object 之后 运行。是不是太快了? (如果这些 objects 的大小只是堆的一小部分怎么办)或更糟:是否为时已晚?如果你说:在堆占用率达到 65% 时触发 collection(默认情况下 G1 在该百分比触发主要 collection,以及其他可能性)。如果在 65% 时您发现大部分 Object 应该更早收集,它们在堆中停留的时间太长了。

你可以看到这很快变得复杂起来。当您了解扫描堆需要时间时,事情会变得更糟,并且当 GC 处于 运行ning 时,您最不想看到的就是应用程序停止。但也请记住,有些收集器 同时 扫描堆,所以他们没有这个问题( ShenandoahZGCC4).

如果可以分离堆,则可以只扫描它的一部分,因此花费的时间很少。人们称他们为“未成年人”collection。一些收集者因此将堆分为“年轻”和“年老”,这种分离是在“婴儿死亡率”的前提下进行的:年轻 objects 死得很快。因此,如果你这样做 separation + young objects die soon,你可以只扫描堆的某个部分,并且在大多数情况下只处理那个部分。这也简化了以下问题的答案:GC 何时应该 运行?年轻当然是吃饱了。

现在直截了当:为什么需要幸存者。让我们假设它不存在。第一个 GC 周期发生了(young region 已满,确切地说我们称之为 Eden),接下来会发生什么? GC 需要告诉那里有什么还活着,将它移到“老年代”,清除 Eden 并重新开始分配。第二个周期进入并做同样的事情,依此类推,直到 GC 说:“老一代如果满了,我就不能再移动了”。这是著名的“老一代”发生的地方。它通常很昂贵。

但是我们确实知道这里的“婴儿死亡率”。我们确实知道,第二个和第三个 GC 周期将一些 objects 移动到老年代,而 本应在第四阶段被收集 。错过了这个机会。因此:幸存者 space。它将 objects 保留在那里“稍长”,然后是单个 GC 周期(称为幸存者年龄),知道在不久的将来这将变成垃圾。因此,不需要经常扫描旧的,只扫描并处理堆的 较小的 部分(EdenSurvivor )。至于为什么有两个个幸存者space,这是一个单独的问题...

实际上,最新的 GC 不需要它。他们找到了一种在您的应用程序 运行ning 时 同时 扫描堆的方法,因此他们没有这些 space。年轻死亡的前提仍然存在,一些 GC 算法可能会使用它;现在或将来。