【问题标题】:Non void Method invoking without assigning return value in Java非 void 方法调用而不在 Java 中分配返回值
【发布时间】:2018-08-30 16:09:29
【问题描述】:

在没有返回值的接收对象的情况下调用非 void 方法时,JVM 会做什么? 它只是在找不到收件人的那一刻销毁返回的对象?还是将返回的对象留给垃圾收集器管理?或者是其他东西?。例如:

public class PrincipalClass {
    public static void main(String[] args) {
        returnStringMethod();
    }
    public static String returnStringMethod() {
        return "Hello, Java world!";
    }
}

“你好,Java 世界!”会发生什么?那被退回了?什么时候销毁?

【问题讨论】:

  • 这个问题在这里可能已经有了答案:stackoverflow.com/questions/23977883/…
  • 没有 Java 方法返回对象,尽管其中许多方法返回对象的引用。如果这样的引用被忽略,那么它就会丢失。作为一个完全独立的问题,VM 中没有实时引用的对象有资格进行垃圾收集。鉴于可以对同一个对象有多个引用,在这个通用级别上,方法的返回值被忽略与它可能引用的任何对象的处置之间没有特定的联系。

标签: java memory-management garbage-collection jvm


【解决方案1】:

假设您点了一顿饭。这顿饭装在一次性盒子里。你把食物拿出来,吃了。现在这些盒子对你没用了。你用它们做什么..?丢弃它们。 Java GC 也是如此。当任何对象没有通过任何对象引用或无法接近时,它会在下次触发 gc 时获取。看到这一点的一种好方法是打开 jvisualvm 并继续跟踪字符串文字,然后触发 gc。您会实时看到事物。

我希望这会有所帮助..!

【讨论】:

  • 哦,好吧,我不知道打开 jvisualvm,感谢@RajanSingh 的额外推荐
【解决方案2】:

在这种情况下,返回的值/引用被简单地丢弃。将其视为立即超出范围的局部变量。

此外,由于没有对此的实时引用,它有资格进行 GC。因此,在未来的某个时间点(不是马上)该对象将被 GCed。

【讨论】:

  • 为了让事情更混乱,这可能被放入字符串池中,因此不会被垃圾收集。
  • 是的,这有点特殊。但总的来说,这是处理对象的方式。
【解决方案3】:

当你编译你的程序时,例如使用javac并运行命令javap -c PrincipalClassjavap是JDK附带的命令),您将看到以下输出:

Compiled from "PrincipalClass.java"
public class PrincipalClass {
  public PrincipalClass();
    Code:
       0: aload_0
       1: invokespecial #1                // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                // Method returnStringMethod:()Ljava/lang/String;
       3: pop
       4: return

  public static java.lang.String returnStringMethod();
    Code:
       0: ldc           #3                // String Hello, Java world!
       2: areturn
}

关键部分是由字节码指令invokestaticpopreturn组成的方法main

invokestatic 指令将调用方法returnStringMethod 并在操作数堆栈上留下对String 的引用。随后的pop 指令将删除最顶层的堆栈条目,即引用。在该指令之后,当前方法中没有对字符串的引用。因此,如果它不是从代码中引用的字符串文字,它就有资格进行垃圾回收。具体来说,它与returnStringMethod() 中的ldc 指令相关联。

原则上这里不需要pop指令,因为return指令会破坏当前方法的整个栈帧,包括它的操作数栈。

在任何一种情况下,答案都是它受制于垃圾收集器,稍后可能会发现没有对该对象的引用。至少它是这样正式运作的。 JVM 中还有一个优化器,它可以检测方法是否忽略直接在被调用方法中创建的对象并优化此特定代码。然而,结果更像是从一开始就没有创建对象,而不是在之后立即销毁它。而且这个优化器只查看与性能相关的代码。

另一点是,对于您的简单程序,垃圾收集器可能永远不会运行,因为在这么短的执行时间内不需要它。 JVM 终止时会立即释放整个堆内存。

【讨论】:

  • 这对于 AOT 编译器也可能是一个简单的优化
猜你喜欢
  • 1970-01-01
  • 2015-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-28
  • 2013-12-01
  • 2015-04-30
相关资源
最近更新 更多