【问题标题】:What happened internally (JVM) when System.gc() or finalize() method called?调用 System.gc() 或 finalize() 方法时,内部 (JVM) 发生了什么?
【发布时间】:2010-10-27 22:03:19
【问题描述】:

调用 System.gc() 或 finalize() 方法时,内部 (JVM) 发生了什么?

这真的是收集垃圾还是降低性能?

【问题讨论】:

  • 请记住,GC 行为依赖于实现,因此它会在 VM 之间发生变化。

标签: java garbage-collection jvm finalize


【解决方案1】:

是 System.gc();如果需要,将触发 finalize() 方法。 公共类 TestGarbageCollection {

public static void main(String[] args) {
    while (true) {
        TestClass s = new TestClass();
        s.display();
        System.gc();
    }
}

}

公共类TestClass {

public TestClass() {
    System.out.println("constructor");
}

public void display() {
    System.out.println("display");
}
@Override
public void finalize() {
    System.out.println("destructor");
}

}

这将触发 finalize() 方法。是否覆盖本地类的 finalize 方法或 Object 的 finalize 方法都会被调用。

【讨论】:

  • 不是真的!!在垃圾收集期间是否应该调用 finalize 方法取决于 JVM。而且根据 Java-doc,调用 System.gc 并不能保证它会立即调用垃圾收集器来释放内存。只是建议!!!
  • @Arun Kumar:尽管 Oracle System.gc() JavaDocs 说:“调用此方法表明 Java 虚拟机花费精力运行已发现被丢弃的对象的 finalize 方法,但其 finalize 方法尚未运行。当控制从方法调用返回时,Java 虚拟机已尽最大努力完成所有未完成的终结。" 最后一句话很清楚。就在它之前的那句话把水搅浑了。我希望他们已经修复了这些文档,因为现在我不知道该怎么想。
【解决方案2】:

finalize() 是一种在对象准备好进行垃圾回收之前执行最后一段代码的方法(当对象没有强引用时)。

那么应该什么时候使用呢? 仅在目前的两种情况下:

  1. 作为安全措施,确保某些服务已关闭或某些 进行所需的最终更改。例如 InputStream 类使用它 关闭 i/o 流。例如,你做了一个 BufferedInputStream 的实例。使用后手动一个是 假设关闭()它。但是因为人们可能会忘记这样做, finalize() 充当了 close() 流的安全网。
  2. 虽然 使用 Native 的。因为垃圾收集器无法控制原生 对象,finalize() 可以用作回收它的一种手段。

除了以上两种情况,千万不要使用它。明白为什么?我们需要了解对象的功能和生命周期。

简介:有一个单独的守护线程称为终结器线程,负责调用 finalize() 方法。终结队列是放置准备调用 finalize() 方法的对象的队列。

  1. 创建对象时,JVM 检查对象是否具有 finalize() 方法。如果有,那么它在内部说明这个特定对象有 finalize() 方法。

当一个对象准备好进行垃圾收集时,垃圾收集器线程会检查该特定对象是否具有来自 (1) 中提到的表的 finalize()。

  • 2a) 如果没有,则将其发送给垃圾回收。

    2b) 它是有的,然后它被添加到终结队列中。它会从表 (1) 中删除对象的条目。

终结器线程不断轮询队列。对于队列中的每个对象,都会调用其 finalize() 方法。在从 (2) 调用 finalize() 循环后,再次重复。如果此对象仍然没有强引用,则发送 GC。如果 然后总是调用 (2a),因为该条目在 (2b) 中被删除

Basically finalize() method is only called once.

那么上面的循环有什么问题呢?

从 (1) 开始。它需要额外的时间来创建对象。 Java 中的内存分配比 malloc/calloc 等快 5 到 10 倍。所有获得的时间都在记录表中的对象等过程中丢失了。我曾经尝试过。在循环中创建 100000 个对象,并在 2 种情况下测量程序终止所需的时间:一种没有 finalize(),第二种有 finalize()。发现它的速度提高了 20%。

来自 (2b):内存泄漏和饥饿。如果队列中的对象引用了大量内存资源,那么除非该对象准备好进行 GC,否则所有这些对象都不会被释放。如果所有对象都是重量级对象,则可能会出现短缺。

来自 (2b):因为 finalize() 只被调用一次,如果在 finalize() 中你有一个对“this”对象的强引用怎么办。下次对象的 finalie() 永远不会被调用,因此可能会使对象处于不一致的状态。

如果在 finalize() 中抛出异常,则将其忽略。

您不知道何时调用 finalize(),因为您无法控制何时调用 GC。有时您可能会在 finalize() 中打印值,但从未显示输出,因为您的程序可能在调用 finalize() 时已经终止。

因此避免使用它。而是创建一个方法说 dispose() 它将关闭必要的资源或用于最终日志等。 the complete post on it。我希望这可以清除。

【讨论】:

  • Stack Overflow 希望您在回答中提供内容,而不仅仅是链接。如果链接断开,您的答案将毫无价值。
  • 完成!!感谢您的建议
【解决方案3】:

System.gc() 清理内存,并使用 finalize() 删除单个对象。

【讨论】:

    【解决方案4】:

    通过调用System.gc(),垃圾收集器运行,正如其名。此时,当对象真正被移除时,会在这些对象消失之前调用finalize()

    最后一个问题中不应包含“or”。这是垃圾收集降低性能。

    通常你根本不应该关心gc,因为它对你来说真的很好。有一些使用场景,你想在某个时间点摆脱很多对象;那么是可行的。

    【讨论】:

    • System.gc() 不一定会调用 GC。这只是对 JVM 的一个建议,即现在是运行 GC 的合适时间,但运行它的最终决定取决于 JVM。
    • 如果您调用 System.gc() 非常低,我预计 gc 不会运行的时间。另一方面 gc 只有在达到阈值时才会完全运行。通过调用 gc() 你通常只是 gc 之前。
    • 使用单个 CPU,如果您使用 System.gc() 并且有很多要清理的内容,那么在清理完成之前,您会看到真正的性能悬崖。如果你运行接近 JVM 任务的内存上限并且它自己会自动执行严重的 GC,这可能会非常痛苦。但是如果你有多个 CPU,性能问题就会少很多,因为 GC 可能会发生在另一个 CPU 上,而你的 JVM 的其余部分会愉快地运行......
    • 确实有链接、信息或证明。我很久没看那些东西了。但是如果 jvm 不使用对象空间分区或类似的东西,您的程序将始终卡在 full gc 上。存在许多技术来尽可能长时间地推迟完整 gc 的时刻,例如世代相传。它们还使完整的 gc 不那么痛苦
    【解决方案5】:

    调用System.gc() 时发生的确切情况取决于JVM。 JVM 将此调用视为建议,它可能是运行垃圾收集器的好时机,所以不要依赖它。

    当 JVM 确定不再有对该对象的可访问引用时,垃圾收集器对该对象运行对象的 finalize() 方法。你不应该在你的代码中调用它。请记住,finalize() 不会在您的程序丢失该最终引用时调用,而是在将来运行垃圾收集器时调用,因此不要依赖它发生在特定的时间点(或根本没有)。

    【讨论】:

      【解决方案6】:

      如果您想了解垃圾回收的内部机制,您应该阅读来自 Sun 的 Hotspot Memory Management Whitepaper

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-01
        • 2018-10-09
        • 2013-10-05
        • 1970-01-01
        • 1970-01-01
        • 2013-09-26
        • 1970-01-01
        相关资源
        最近更新 更多