我需要知道在JVM
中何时调用finalize()
方法。我创建了一个测试类,通过覆盖finalize()
方法将其写入文件,但它未被执行。有人可以告诉我为什么它没有被执行吗?
我需要知道在JVM
中何时调用finalize()
方法。我创建了一个测试类,通过覆盖finalize()
方法将其写入文件,但它未被执行。有人可以告诉我为什么它没有被执行吗?
finalize
方法在对象准备进行垃圾回收时被调用。这可能是在对象符合垃圾回收条件后的任何时间。
请注意,一个对象可能永远不会被垃圾收集(因此也不会调用finalize
)。这种情况可能发生在对象从未符合垃圾回收条件(因为它在JVM的整个生命周期内都是可达的)或当对象变得符合条件与JVM停止运行之间没有进行垃圾回收(这通常出现在简单的测试程序中)。
有办法告诉JVM在尚未调用finalize
的对象上运行它,但使用它们也不是一个好主意(那个方法的保证也不是非常强)。
如果你依赖finalize
来确保应用程序的正确操作,那么你做错了什么。 finalize
应该仅用于清理(通常是非Java的)资源。这正是因为JVM不能保证在任何对象上调用finalize
。
System.gc()
来调用FileInputStream::finalize(),然后才能移动文件。 - Elistfinalize()
来进行任何清理等操作。正如Joachim所指出的那样,如果对象始终可访问,则在程序生命周期内可能永远不会发生这种情况。当垃圾回收确定没有对该对象的引用时,由垃圾回收器在对象上调用。
finalize()
可能不是通用的最佳方法。finalize
方法在哪些情况下会有用? - nbrofinalize()
方法会被调用,而不是当主方法终止时调用。此外,主类在应用程序完成之前可能会被垃圾收集;比如,在多线程应用中,“主”线程创建其他线程然后返回。(实际上,需要使用非标准类加载器...) - Stephen C
protected void finalize() throws Throwable {}
- every class inherits the
finalize()
method from java.lang.Object- the method is called by the garbage collector when it determines no more references to the object exist
- the Object finalize method performs no actions but it may be overridden by any class
- normally it should be overridden to clean-up non-Java resources ie closing a file
if overridding
finalize()
it is good programming practice to use a try-catch-finally statement and to always callsuper.finalize()
. This is a safety measure to ensure you do not inadvertently miss closing a resource used by the objects calling class
protected void finalize() throws Throwable { try { close(); // close open files } finally { super.finalize(); } }
any exception thrown by
finalize()
during garbage collection halts the finalization but is otherwise ignoredfinalize()
is never run more than once on any object
引用自: http://www.janeg.ca/scjp/gc/finalize.html
你也可以查看这篇文章:
Java中的finalize()
方法不是解构函数,不能用于处理应用程序依赖的逻辑。Java规范说明,在应用程序的生命周期内不能保证finalize
方法被调用。
你可能需要的是finally
和清理方法的组合,如下:
MyClass myObj;
try {
myObj = new MyClass();
// ...
} finally {
if (null != myObj) {
myObj.cleanup();
}
}
当MyClass()
构造函数抛出异常时,这将正确处理该情况。
MyClass()
构造函数抛出异常的情况。这将在示例的新版本中触发NPE。 - rsp请参阅Effective Java第二版的第27页。 第7条:避免使用finalizer(终结方法)
finalizer是不可预测的、常常是危险的,而且通常也是不必要的。在finalizer中不要执行任何时间关键的操作,在finalizer中也不要依赖于更新关键持久状态。
要终止资源,请改用try-finally:
// try-finally block guarantees execution of termination method
Foo foo = new Foo(...);
try {
// Do what must be done with foo
...
} finally {
foo.terminate(); // Explicit termination method
}
finalize()
方法是在对象被垃圾收集器检测到不再可达时调用,并在回收对象使用的内存之前调用。
如果一个对象永远不会变得不可达,则永远不会对其调用finalize()
方法。
如果垃圾收集器没有运行,则可能永远不会调用finalize()
方法。(通常,只有当JVM判断可能存在足够多的垃圾时,才会运行垃圾收集器。)
可能需要多个垃圾收集周期才能确定特定对象已不可达。(Java垃圾回收器通常是“分代”收集器...)
一旦垃圾收集器检测到对象不可达且可终结,它就会将其放置在终结队列上。终结通常与正常的垃圾回收异步发生。
(JVM规范实际上允许JVM永远不运行finalizer,只要它不回收对象使用的空间。以这种方式实现的JVM将被禁用/无用,但此行为是“允许”的。)
总之,依赖终结来完成必须在明确时间范围内完成的事情是不明智的。最好根本不使用他们。应该有更好(即更可靠)的方法来完成您要在finalize()
方法中尝试完成的任何操作。close()
...)我创建了一个测试类,当覆盖finalize()方法时会将内容写入文件。但是它没有被执行。有可能的原因有以下几种:
由于JVM对finalize()方法的调用存在不确定性(无法确定是否执行重写的finalize()方法),因此为了研究目的,更好的观察finalize()方法被调用时发生的情况是通过命令System.gc()强制JVM进行垃圾回收。
具体来说,当对象不再使用时,finalize()方法将被调用。但是,当我们尝试通过创建新对象来调用它时,无法确定其是否被调用。因此,为了确定性,我们创建一个无用的null对象c,因此我们可以看到对象c的finalize()方法的调用。
示例
class Car {
int maxspeed;
Car() {
maxspeed = 70;
}
protected void finalize() {
// Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
// Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection
System.out.println("Called finalize method in class Car...");
}
}
class Bike {
int maxspeed;
Bike() {
maxspeed = 50;
}
protected void finalize() {
System.out.println("Called finalize method in class Bike...");
}
}
class Example {
public static void main(String args[]) {
Car c = new Car();
c = null; // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
Bike b = new Bike();
System.gc(); // should clear c, but not b
for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
System.out.print("\t" + b.maxspeed);
if (b.maxspeed > 50) {
System.out.println("Over Speed. Pls slow down.");
}
}
}
}
输出
Called finalize method in class Car...
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51Over Speed. Pls slow down.
52Over Speed. Pls slow down.
53Over Speed. Pls slow down.
54Over Speed. Pls slow down.
55Over Speed. Pls slow down.
56Over Speed. Pls slow down.
57Over Speed. Pls slow down.
58Over Speed. Pls slow down.
59Over Speed. Pls slow down.
60Over Speed. Pls slow down.
61Over Speed. Pls slow down.
62Over Speed. Pls slow down.
63Over Speed. Pls slow down.
64Over Speed. Pls slow down.
65Over Speed. Pls slow down.
66Over Speed. Pls slow down.
67Over Speed. Pls slow down.
68Over Speed. Pls slow down.
69Over Speed. Pls slow down.
70Over Speed. Pls slow down.
注意 - 即使打印了70次并且在程序中不再使用对象b,仍然存在JVM未清除b的不确定性,因为“调用Bike类中的finalize方法…”没有被打印。
System.gc();
并不能保证垃圾回收一定会被执行。 - Simon Forsbergfinalize将打印出类创建的计数。
protected void finalize() throws Throwable {
System.out.println("Run F" );
if ( checkedOut)
System.out.println("Error: Checked out");
System.out.println("Class Create Count: " + classCreate);
}
主函数
while ( true) {
Book novel=new Book(true);
//System.out.println(novel.checkedOut);
//Runtime.getRuntime().runFinalization();
novel.checkIn();
new Book(true);
//System.runFinalization();
System.gc();
正如您所看到的。以下输出显示当类计数为36时,gc首次执行。
C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F
最终思考
Finalize方法不可靠,但仅可用于一件事。您可以确保在对象被垃圾收集之前已关闭或释放,从而使得能够在正确处理涉及生命周期结束操作的对象的复杂生命周期的情况下实现故障安全。这是我所想到的唯一使它值得覆盖的原因。
protected void finalize(){
// This is where the finalization code is entered
}
finalize()
和垃圾回收并没有任何影响。 - ha9u63a7