繁体   English   中英

Java - 正在执行方法的对象可以被垃圾收集吗?

[英]Java - Can objects which are executing methods be garbage-collected?

在 Java 中,我没有考虑太多就做了以下事情:

public class Main {

    public void run() {
        // ...
    }

    public static void main(String[] args) {
        new Main().run();
    }
}

但是,最近我不确定这样做是否安全。 毕竟,在创建后没有对Main对象的引用(好吧,有this引用,但这算不算?),所以看起来垃圾收集器可能会在对象处于中间时删除它的危险执行某事。 所以也许main方法应该是这样的:

    public static void main(String[] args) {
        Main m = new Main();
        m.run();
    }

现在,我很确定第一个版本可以工作,而且我从来没有遇到过任何问题,但我想知道在所有情况下这样做是否安全(不仅在特定的 JVM 中,而且最好根据语言规范对此类情况的说明)。

如果正在执行对象方法,则意味着有人拥有该引用。 所以不,在执行方法时不能对对象进行 GC。

大多数情况下,垃圾收集是透明的。 它可以消除手动内存管理的不必要的复杂性。 所以,它看起来不会被收集,但实际发生的事情更加微妙。

简单地说,编译器可以完全省略对象的构造。 (通过编译器,我的意思是比 javac 更低级别的编译器。字节码将是源的字面音译。)更晦涩的是,垃圾收集通常在单独的线程中运行,并且实际上删除未访问的对象,因为它正在运行一个方法。

如何观察? 终结者中的常见嫌疑人。 它可以与在对象上运行的方法同时运行。 通常你会在终结器和普通方法中使用synchronized块来解决这个问题,这引入了必要的发生前关系。

m 只是一个存储了引用的变量。 这将被程序员用来进一步使用同一个对象来在同一个对象上编写逻辑。

执行时,程序将转换为 OP-CODES / INSTRUCTIONS 。 这些 INSTRUCTION 将引用对象(毕竟它是一个内存位置)。 如果存在 m,则将通过 INDIRECT REFERENCE 访问对象的位置。 如果 m 不存在,则引用为 DIRECT。

所以在这里,对象正在被 CPU 寄存器使用,而与引用变量的使用无关。

这将一直可用,直到执行流程在 main() 函数的范围内。

此外,按照 GC 过程,GC 只会从内存中删除对象,一旦 GC 确定不会再使用该对象。

每个对象都有机会生存多次(取决于情况和算法)。 一旦机会次数结束,则只有对象被垃圾收集。

简单来说,最近使用过的对象将有机会留在内存中。 旧对象将从内存中删除。

所以给定你的代码:

public class Main {

public void run() {
    // ...
}

public static void main(String[] args) {
    new Main().run();
}
}

该对象不会被垃圾收集。

此外,对于示例,请尝试查看匿名类示例。 或者来自 AWT / SWING 中事件处理的示例。

在那里,您会发现很多这样的用法。

接受的答案不正确。 对象是否可以被 GC 取决于您的public void run() {// ...}方法是否具有对类实例 (this) 的引用。 尝试:

public class FinalizeThis {

    private String a = "a";

    protected void finalize() {
        System.out.println("finalized!");
    }

    void loop() {
        System.out.println("loop() called");
        for (int i = 0; i < 1_000_000_000; i++) {
            if (i % 1_000_000 == 0)
                System.gc();
        }
        // System.out.println(a);
        System.out.println("loop() returns");
    }

    public static void main(String[] args) {
        new FinalizeThis().loop();
    }
}

上面的程序总是输出

loop() called
finalized!
loop() returns

在 Java 8 中。但是,如果您取消System.out.println(a)注释,输出将更改为

loop() called
a
loop() returns

这次没有GC,因为调用的方法引用了实例变量(this.a)。

你可以看看这个答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM