Java中System.gc()和finalize()方法有什么区别?

15

我对java的system.gc()和finalize()方法感到困惑。 我们无法强制JVM收集垃圾对象。我们可以在java代码中编写这两种方法,如果两者都用于垃圾回收,那么Java提供两种垃圾回收方法的意义是什么?

请告诉我这两种方法的精确工作方式以及内部如何工作。


你看过Javadoc文档或者查看了其他的问题吗? - Kru
2
这些方法彼此之间关系不大。它们互不调用,且具有完全不同的目的。 - Peter Lawrey
8个回答

13

System.gc()会请求系统进行垃圾回收。Javadoc指出:

运行垃圾回收器。

你无法控制垃圾回收器的“工作强度”。垃圾回收器内部的工作方式是与VM有关的,并且是一个研究课题。但通常会进行一些较小的“增量”回收和一些“完全”的垃圾回收。因此,请将System.gc视为请求,但不能保证对象的垃圾回收一定会发生。

Object.finalize()可以被覆盖以指定在给定对象被垃圾回收时要执行的操作(实际上是在它被垃圾回收之前要执行的操作)。Javadoc指出:

当GC确定不再有对该对象的引用时,由垃圾回收器在对象上调用。

finalizer的经典用途是在对象被垃圾回收时释放系统资源,例如释放文件句柄、临时文件等。

请勿使用finalizer来在JVM退出时执行操作。为此,请使用通过Runtime.getRuntime().addShutdownHook(Thread)注册的关闭挂钩。


JVM 对于你对 System.gc() 的调用中的任何“友好”或“礼貌”都是无感知的。如果你粗鲁地进行调用,它也会以同样的方式工作 :-) - Stephen C
@StephenC 是的 :) 我的意思是你依赖于垃圾收集器的善意,根据需求回收空间:"Java虚拟机已经尽最大努力从所有废弃对象中回收空间"。你无法控制它的尝试程度 :) - ewernli

2

System.gc() 强制执行垃圾回收,而您对象的 Finalize() 方法定义了垃圾回收器在收集此特定对象时应执行的操作。

简单来说,就是这样:

class MyClass {
    public UnmanagedResource resource;

    void Finalize() {
        FreeUnmanagedResource(resource);
    }
}

MyClass[] data = new MyClass[1000];
for(int i=0; i<1000; i++) {
    data[i] = new MyClass();
}
//do some work
data = null;
System.gc(); //Note that it doesn't guarantee you that all MyClass instances will be actually collected at this point.

1
System.gc() 绝对不会强制运行 GC。它只是通知 GC 应用程序想要运行 GC,但不能保证任何事情会发生。 - ctomek

1

system.gc() 方法通知JVM可以运行垃圾回收器来通过删除未使用的对象来清除内存。根据Java文档:

调用gc方法建议Java虚拟机花费精力回收未使用的对象,以便使它们当前占用的内存可用于快速重用。当从方法调用返回时,Java虚拟机已尽最大努力从所有丢弃的对象中回收空间。

finalize() 方法不会触发垃圾回收器,而是在垃圾回收器即将销毁对象时调用。它提供了清除对象的指令。


1

System.gc()方法用于垃圾回收由new关键字创建的对象,而finalize()方法用于垃圾回收未使用new关键字创建的对象。所以,我猜这回答了你的问题。


1
这里的答案很好,只是想详细说明一下 finalize() 方法:永远不要使用它。它的执行根本不能保证,并且最终使用 finalize() 会增加性能损失。
正如 Joshua Bloch 在《Effective Java》中所写:
“Finalizers 是不可预测的、常常危险的,而且通常是不必要的。永远不要在 finalizer 中做任何时间关键的事情。永远不要依赖 finalizer 来更新关键的持久状态。”
还有:
“哦,还有一件事:使用 finalizer 会有严重的性能损失。在我的机器上,创建和销毁一个简单对象的时间大约为 5.6 纳秒。添加 finalizer 将时间增加到 2,400 纳秒。换句话说,使用 finalizer 创建和销毁对象的速度慢了约 430 倍。”
建议使用以下资源终止 try-finally 模式,这些模式可以保证运行:
Bar bar = new Bar(...);
try {
    // Your code here
} finally {
    bar.releaseResource(); // You implementation. For example close connection
}

0

垃圾回收用于回收对象的已分配内存,Finalize() 在回收内存之前被垃圾回收器调用,Finalize() 方法通常用于在删除对象之前执行某些操作。


1
当finalize()被调用时,对象仍然可用,并且这是一个很好的地方,通过将对象重新引用到其他对象来制造难以发现的内存泄漏。 - heikkim

0

有许多包含finalize()方法的类,我假设您指的是Object类中的方法。当您想要运行Java的垃圾编译器时,可以使用System.gc()。它每隔几分钟就会自动运行,但您也可以在需要时调用它。当垃圾收集器运行时,它会对每个没有引用的对象调用finalize()方法。基本上,System.gc()会清理内存并使用finalize()来消除单个对象。


0

垃圾收集器是通过在任何类上调用System.gc()方法来调用的。但它不能保证在jvm关闭之前所有被置空的对象都将被垃圾收集。因此,gc()方法只会垃圾收集使用new关键字创建的对象。使用其他逻辑创建的对象将在调用gc调用垃圾收集器之前显式调用finalize()方法进行垃圾收集。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接