如果保证在收集时调用 finalize() ,年轻代是否仍然具有速度优势?

Is young generation still gets speed advantage if finalize() is guaranteed to be called when collecting?

为什么年轻代的垃圾收集速度快取决于一个事实:年轻代的大多数对象很快就会死亡。所以当年轻代收集发生时,很少有还活着的对象被移动到老年代,从那时起,年轻代中的所有数据都可以被认为是无用的(部分或它们被移动,重置不可达),这无需进一步扫描即可重新使用内存的和平。在这种情况下,不会扫描无法访问的对象,从而节省大量时间。

但是我有一个问题,在 Java 中有一个方法 finalize() (虽然它在 JAVA 9 中被弃用),如果收集器保证 finalize() 将被调用时,它需要扫描无法到达的对象,而不仅仅是遍历活体对象,速度优势似乎消失了。

所以,

  1. 我说的对吗? (finalize() 使得新生代收集 速度变慢,速度优势消失。)
  2. 如果不是,JVM 是如何处理这个问题的? (例如,忽略 finalize()?)
  3. young generation除了上面的问题还有其他的吗 优势?

编辑: 我正在为具有 finalize() 功能的语言编写 gc,在这种情况下我无法快速收集。

基本上,你做对了。但是幸存者对象不会立即复制到老年代。相反,它们被复制到 Survivor space,在它们被提升到老年代之前,它们必须在可配置数量的垃圾收集中存活下来。

但基本假设是正确的。当对象存活时间超过必要时间并且必须调用 finalize() 延长对象的生命周期时,效率会降低。

根本的解决方法是将此作为例外情况。这甚至在 the specification:

中得到解决

For efficiency, an implementation may keep track of classes that do not override the finalize method of class Object, or override it in a trivial way.

For example:

protected void finalize() throws Throwable {
    super.finalize();
}

We encourage implementations to treat such objects as having a finalizer that is not overridden, and to finalize them more efficiently, as described in §12.6.1.

在 HotSpot JVM 的情况下,它会识别何时由 Object 继承的方法未被覆盖或何时被空方法覆盖。 Afaik,单独的 super 调用并不总是被识别,但对于您自己的语言,它可能会被识别。

所以对于Java中的大部分对象来说,finalize()不需要调用,因为它无论如何都没有效果,也永远不会被调用。这解决了延长生命周期的问题,因为它现在只适用于少数对象。

通过拥有一个特殊的引用对象来消除扫描死对象的需要,该引用对象仅为那些具有非平凡的终结器的对象创建,它本身保持可达。所以它仍然只是必须扫描的可达对象。可以在 .

中找到更多详细信息