我需要知道什么时候在JVM中调用finalize()方法。我创建了一个测试类,当finalize()方法被重写时写入文件。它没有被执行。有人能告诉我为什么它不能执行吗?


当前回答

在最近与终结器方法搏斗之后(为了在测试期间处理连接池),我不得不说终结器缺少很多东西。使用VisualVM来观察以及使用弱引用来跟踪实际的交互,我发现以下事情在Java 8环境中是正确的(Oracle JDK, Ubuntu 15):

Finalize is not called immediately the Finalizer (GC part) individually owns the reference elusively The default Garbage Collector pools unreachable objects Finalize is called in bulk pointing to an implementation detail that there is a certain phase the garbage collector frees the resources. Calling System.gc() often does not result in objects being finalized more often, it just results in the Finalizer getting aware of an unreachable object more rapidly Creating a thread dump almost always result in triggering the finalizer due to high heap overhead during performing the heap dump or some other internal mechanism Finalization seams to be bound by either memory requirements (free up more memory) or by the list of objects being marked for finalization growing of a certain internal limit. So if you have a lot of objects getting finalized the finalization phase will be triggered more often and earlier when compared with only a few There were circumstances a System.gc() triggered a finalize directly but only if the reference was a local and short living. This might be generation related.

最后认为

最后确定方法是不可靠的,但只能用于一件事。您可以确保在垃圾收集之前关闭或释放对象,从而在正确处理涉及生命结束操作的更复杂生命周期的对象时实现故障安全。这是我能想到的一个值得我们去推翻它的原因。

其他回答

由于JVM调用finalize()方法存在不确定性(不确定被重写的finalize()是否会被执行),为了研究目的,观察finalize()调用时发生的情况的更好方法是通过命令System.gc()强制JVM调用垃圾收集。

具体来说,finalize()在对象不再使用时被调用。但是当我们试图通过创建新对象来调用它时,它的调用是不确定的。因此,为了确定起见,我们创建了一个空对象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在程序中没有被使用,也不确定b是否被JVM清除,因为“调用的finalize方法在类Bike…”没有打印。

一般来说,最好不要依赖finalize()来做任何清理等。

根据Javadoc(值得一读),它是:

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

正如Joachim指出的,如果对象总是可访问的,那么在程序的生命周期中,这可能永远不会发生。

此外,垃圾收集器不保证在任何特定时间运行。一般来说,我想说的是finalize()可能不是最好的方法,除非有特定的事情需要它。

Sometimes when it is destroyed, an object must make an action. For example, if an object has a non-java resource such as a file handle or a font, you can verify that these resources are released before destroying an object. To manage such situations, java offers a mechanism called "finalizing". By finalizing it, you can define specific actions that occur when an object is about to be removed from the garbage collector. To add a finalizer to a class simply define the finalize() method. Java execution time calls this method whenever it is about to delete an object of that class. Within the finalize method() you specify actions to be performed before destroying an object. The garbage collector is periodically searched for objects that no longer refer to any running state or indirectly any other object with reference. Before an asset is released, the Java runtime calls the finalize() method on the object. The finalize() method has the following general form:

protected void finalize(){
    // This is where the finalization code is entered
}

使用protected关键字,finalize()类之外的代码可以阻止对finalize()的访问。 务必要理解finalize()是在垃圾收集之前调用的。例如,当对象离开作用域时,它不会被调用。这意味着您无法知道finalize()何时或是否将执行。因此,程序必须提供其他方法来释放系统资源或对象使用的其他资源。不应该依赖finalize()来实现程序的正常运行。

An Object becomes eligible for Garbage collection or GC if its not reachable from any live threads or any static refrences in other words you can say that an object becomes eligible for garbage collection if its all references are null. Cyclic dependencies are not counted as reference so if Object A has reference of object B and object B has reference of Object A and they don't have any other live reference then both Objects A and B will be eligible for Garbage collection. Generally an object becomes eligible for garbage collection in Java on following cases:

该对象的所有引用显式设置为空,例如object = null 对象在块内创建,一旦控件退出该块,引用就会离开作用域。 父对象设置为空,如果一个对象持有另一个对象的引用,并且当您将容器对象的引用设置为空时,子对象或包含对象自动符合垃圾收集的条件。 如果一个对象只有通过WeakHashMap的活动引用,那么它就有资格进行垃圾收集。

查看Effective Java,第2版第27页。 第7项:避免终结词

终结器是不可预测的,通常是危险的,而且通常是不必要的。永远不要在终结器中做任何时间紧迫的事情。从来没有 依赖终结器更新关键持久状态。

要终止一个资源,请使用try-finally:

// try-finally块保证终止方法的执行 Foo Foo =新的Foo(…); 尝试{ //用foo做必须做的事情 ... }最后{ foo.terminate ();//显式终止方法 }