我对最终定稿的理解是:
为了清理或回收对象占用的内存,垃圾收集器开始运行。 (自动调用?)
垃圾收集器然后取消引用该对象。有时,垃圾收集器无法访问该对象。然后调用finalize进行最后的清理处理,之后可以调用垃圾收集器。
这是对最终确定的准确描述吗?
答案 0 :(得分:15)
垃圾收集器在后台自动运行(尽管可以显式调用它,但对此的需求应该很少)。它基本上只清理其他对象没有引用的对象(授予,完整图片更复杂,但这是基本的想法)。因此它不会更改任何活动对象中的任何引用。如果无法从任何活动对象访问对象,则意味着可以安全地进行垃圾回收。
终结 意味着清理对象获取的资源(不是内存,而是其他资源,例如文件句柄,端口,数据库连接等)。然而,它并没有真正解决: - (
finalize()
finalize()
!因此,即使保证被调用,它也不是一个释放资源的好地方:当它被调用以释放你打开的所有数据库连接时,系统可能已经用完了免费连接完全,你的应用程序不再有效。
答案 1 :(得分:7)
来自this article:
任何类的实例 实现finalize()方法 通常称为可终结的对象。他们 不会立即收回 他们的Java垃圾收集器 不再引用。相反, Java垃圾收集器附加了 对象到特殊队列 最终确定过程。通常是 由一个叫做a的特殊线程执行 某些Java上的“引用处理程序” 虚拟机。在这 完成过程,“终结者” 线程将执行每个finalize() 对象的方法。仅在那之后 圆满完成了 finalize()方法将是一个对象 交给Java垃圾 收集它的空间回收 通过“未来”垃圾收集。
你可以自由地做任何事情 在你的finalize()方法中 类。当你这样做时,请不要 期望占用的内存空间 每个要回收的物体 当Java垃圾收集器的时候 对象不再被引用或不被引用 需要更久。为什么?它不是 保证finalize()方法 将及时完成执行 方式。最坏的情况,它可能不是偶数 即使没有更多,也会被调用 对象的引用。这意味着 它不能保证任何物体 有一个finalize()方法是 垃圾收集。
另外,来自Sun的this article有一些很好的图表来解释这个过程。
答案 2 :(得分:6)
不。仅当垃圾收集器尝试回收您的对象时才运行finalize()
方法。
您的对象使用的任何内存(通常,我都不会想到异常)会自动连接到您的对象并随之清理。因此,终结并不意味着释放内存,而是释放您的对象可能与之关联的任何其他资源。例如,这可以用于关闭打开的文件或数据库连接,或者运行一些与操作系统连接的低级代码,以释放一些系统级资源。
答案 3 :(得分:5)
实际上,这是finalize()方法的行为:
一旦垃圾收集器运行(VM决定它需要释放内存,你不能强制它运行)并决定从这个对象收集内存(这意味着没有任何引用指向它,来自可达对象至少),在它删除它占用的内存之前,它在对象上运行方法finalize()。你可以确定,如果收集垃圾,对象将在它消失之前运行finalize(),但你不能确定它会完全得到GC,所以你不应该依赖这个方法来进行任何消毒。 。您应该在finally {}块中运行清理语句,而不是使用finalize(),因为它不能保证运行。
此外,有些人已经完成了性能测试并且表明finalize方法在某种程度上减慢了对象的创建/破坏。我不记得来源所以对待这个信息不太可靠。 :)
答案 4 :(得分:2)
Finalization用于清理垃圾收集器无法释放的资源。例如,考虑一个直接从OS分配(通过一些native
API)资源的程序。这通常会产生某种“句柄”(UNIX文件描述符或Windows HANDLE,或类似的东西):
class Wrapper {
private long handle;
private Handle(long h) {
handle = h;
}
private static native long getHandleFromOS();
static Wrapper allocate() {
return new Handle(getHandleFromOS());
}
}
那么,如果您的代码分配了类Wrapper
的实例,会发生什么?那么类会分配某种特定于操作系统的资源,并在成员变量中保持对它(句柄)的引用。但是,当对包装器实例的最后一次Java引用丢失时会发生什么?现在,垃圾收集器将(在某些时候)回收现已解散的包装器实例的空间。但是包装器分配的OS资源会发生什么?它会在上面的场景中泄露,如果它是一个昂贵的资源,例如文件描述符,这将是一件坏事。
为了在这种情况下允许您的代码清理,有finalize
方法。
class Wrapper {
private long handle;
private Handle(long h) {
handle = h;
}
protected void finalize() {
returnHandleToOS(handle);
}
private static native long getHandleFromOS();
private static native void returnHandleToOS(long handle);
static Wrapper allocate() {
return new Handle(getHandleFromOS());
}
}
现在,当GC回收包装器实例的空间时,终结器确保资源正确地返回到操作系统。
这听起来很不错,但正如其他人已经指出的那样,缺点是,终结本质上是不可靠的:你不知道终结者何时会被运行。更糟糕的是:根本无法保证它会被运行。因此,最好提供dispose
机制并仅将最终化用作安全网,以防您的班级客户忘记妥善处理他们的参考文件:
class Wrapper {
private long handle;
private Handle(long h) {
handle = h;
}
protected void finalize() {
if( handle != 0 ) returnHandleToOS(handle);
}
public void dispose() {
returnHandleToOS(handle);
handle = 0;
}
private static native long getHandleFromOS();
private static native void returnHandleToOS(long handle);
static Wrapper allocate() {
return new Handle(getHandleFromOS());
}
}