Java – 可以对执行方法的对象进行垃圾回收吗?

在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中事件处理的示例。

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