我对finalization的理解是:
为了清除或回收对象占用的内存,垃圾回收器会开始工作。(自动调用?)
然后,垃圾回收器会取消对象的引用。有时,垃圾回收器无法访问对象。那么,将调用finalize进行最终的清理处理,之后才能唤醒垃圾回收器。
以上描述准确吗?
我对finalization的理解是:
为了清除或回收对象占用的内存,垃圾回收器会开始工作。(自动调用?)
然后,垃圾回收器会取消对象的引用。有时,垃圾回收器无法访问对象。那么,将调用finalize进行最终的清理处理,之后才能唤醒垃圾回收器。
以上描述准确吗?
垃圾收集器会在后台自动运行(虽然它可以被显式地调用,但这种需要是很少的)。它主要清理那些没有被其他对象引用的对象(当然,整个过程更为复杂,但这是基本思想)。因此,它不会更改任何活动对象中的引用。如果一个对象无法从任何活动对象访问,这意味着它可以被安全地回收。
终结器本来是用来清理对象获取的资源(不包括内存,而是其他资源,例如文件句柄、端口、数据库连接等)的。然而,这并没有真正起作用:-(
finalize()
什么时候被调用是不可预测的 finalize()
会被调用!因此,即使有保证会被调用,它也不是释放资源的好地方:等它被调用时要释放所有已打开的数据库连接,系统可能已经完全耗尽了空闲连接,你的应用程序就不能再工作了。
finalize()
方法。实际上,finalize()方法的行为如下:
当垃圾收集器运行(虚拟机决定需要释放内存,但无法强制运行)并决定从该对象中收集内存时(这意味着至少从可达对象中没有指向它的引用),就在删除它所占用的内存之前,在对象上运行finalize()方法。您可以确信,如果被垃圾回收,对象将在消失之前运行finalize(),但是您不能确定它是否会被GC'ed,因此不应依赖该方法进行任何清理。您应该在finally {}块内运行清理语句,而不使用finalize(),因为不能保证其运行。
此外,一些人进行了性能测试,并显示finalize()方法会稍微减慢对象的创建/销毁速度。我无法记住来源,因此请将此信息视为不太可靠。:)
finally
。 - Tom Hawtin - tacklineFinalization被用于清理资源,这些资源不能被垃圾回收器释放。例如,考虑一个程序,它通过某些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引用丢失时会发生什么?现在,垃圾回收器将(在某个时间点)回收现在无效的包装器实例的空间。但是,分配给包装器的操作系统资源会怎样呢?在上述情况下,它将泄漏,如果它是昂贵的资源,例如文件描述符,则这是一件坏事。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());
}
}
这听起来非常不错,但正如其他人已经指出的那样,缺点是终结化本质上是不可靠的:您不知道何时运行终结器。更糟糕的是:无法保证它会被完全运行。因此,最好提供一个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());
}
}