使用 gc() 方法后未调用 Java finalize() 方法?

Java finalize() method is not called after using gc() method?

提问人:Sanku 提问时间:7/17/2016 最后编辑:Vladimir VagaytsevSanku 更新时间:7/17/2016 访问量:334

问:

为了查看 java 中在对象即将被销毁时调用的方法的工作,我编写了以下程序finalize()

class counterTest{
    public static int count;
    public counterTest(){
        count++;
    }
}

public class finalize {

    public static void main(String args[]){

        counterTest obj1=new counterTest();
        System.out.println("Number of objects :" + counterTest.count);
        counterTest obj2=new counterTest();
        System.out.println("Number of objects :" + counterTest.count);
        Runtime rs=Runtime.getRuntime();
        obj1=null;
        obj2=null;
        rs.gc();
    }
    protected void finalize(){
        System.out.println("Program about to terminate");
        counterTest.count--;
        System.out.println("Number of objects :" + counterTest.count);
    }
}

我预计输出是这样的

Number of objects :1 
Number of objects :2 
Program about to terminate 
Number of objects :1 
Program about to terminate 
Number of objects :0

但我只得到了前两行。由于我正在使对象引用为 null,然后调用该方法,因此我希望应该显示 inside 方法中编写的语句。这是否意味着不能保证每次使用方法时都会调用方法。gc()finalize()finalize()gc()

爪哇岛

评论

3赞 gevorg 7/17/2016
调用 gc 并不能保证最终执行,但它只是建议。
2赞 catch23 7/17/2016
@Sai 查看 java 代码约定
0赞 gevorg 7/17/2016
如何在 Java 中强制垃圾回收的可能重复?
0赞 Vladimir Vagaytsev 7/17/2016
请看 J. Bloch 的 “Effective Java” 2nd edition, Item 7, p.27,它对定稿器给出了很好的解释

答:

2赞 Alexander Petrov 7/17/2016 #1

您的 finalize 方法应该在 counterTest 中,然后它将“可能”被调用。您从未真正创建过“finalize”类的实例。因此,您的 finalize 方法永远没有机会被执行。

以下是更新后的代码,应按预期工作:

class counterTest{
    public static int count;
    public counterTest(){
        count++;
    }

    protected void finalize(){
        System.out.println("Program about to terminate");
        counterTest.count--;
        System.out.println("Number of objects :" + counterTest.count);
    }
}

public class Finalize {

    public static void main(String args[]){

        counterTest obj1=new counterTest();
        System.out.println("Number of objects :" + counterTest.count);
        counterTest obj2=new counterTest();
        System.out.println("Number of objects :" + counterTest.count);
        Runtime rs=Runtime.getRuntime();
        obj1=null;
        obj2=null;
        rs.gc();
    }

}

应该注意的是,“finalize”方法并不意味着要被覆盖,因为它们不可靠。你永远不知道垃圾回收器什么时候会收集一个特定的对象,所以在它上面中继以关闭你的数据库连接或做其他类似的事情是一个不,不,不......

评论

0赞 Sanku 7/17/2016
谢谢你现在的工作。但是为什么 finalize() 方法应该在我们为其创建对象的类中。我的意思是,如果我们有 10 个类,那么每个类是否有必要有 10 个 finalize() 方法?
1赞 user207421 7/17/2016
它可以被调用。没有什么可以保证 GC 会被调用,更不用说最终确定了。
1赞 user207421 7/17/2016
@SaiSankalp 这没有意义。每个类一个方法。finalize()
0赞 Sanku 7/17/2016
@EJP我就是这么想的。因此,我们不能保证每次我们将对象引用保持为null时都会被调用gc(),对吗?
0赞 Alexander Petrov 7/17/2016
@Sai Java 中的 finalize() 方法“在实践中”从未真正用于做任何事情。使用它们的主要是垃圾回收器。没有人期望您将覆盖 10 个不同类中的 10 个 finalize 方法。大多数时候,在我的职业生涯中,我看到有人覆盖finalize(),这总是一个错误。
2赞 hyde 7/17/2016 #2

首先,您的代码没有类的实例(AKA 对象)。 方法是静态的,没有实例。finalizemain

但是,即使你确实有一个实例,在 Java GC 中,调用方法也不是很有确定性或保证的。它不是类似于 C++ 的析构函数。因此,即使您将方法添加到类中,其中创建了一些实例,也不能保证它会被调用。finalize()finalize()counterTest

如果想要与析构函数类似的行为,则需要围绕 try-with-resources 模式设计代码。然后 AutoCloseable 接口的 close() 方法扮演析构函数的角色。

在Java中有一个非常强的约定,即在类名中使用所谓的Pascal大小写,所以你的类应该命名为和。CounterTestFinalize