Java 您是否通过在方法中将变量声明为属性来保存垃圾收集器的工作?

Java 您是否通过在方法中将变量声明为属性来保存垃圾收集器的工作?,java,performance,memory,Java,Performance,Memory,比较 到 假设大量调用了addToA方法,那么您是否使用第二个方法来节省垃圾收集器的工作(并加快程序的速度)?在堆栈上分配局部变量 在这种情况下 public class Core { int b; public int addToA(int a) { b = a + 2; return b; } } public int addToA(int a) { int b = a + 2; return b; } 当该方法

比较


假设大量调用了
addToA
方法,那么您是否使用第二个方法来节省垃圾收集器的工作(并加快程序的速度)?

在堆栈上分配局部变量

在这种情况下

public class Core {

    int b;

    public int addToA(int a) {
        b = a + 2;
        return b;
    }
}
public int addToA(int a) {
    int b = a + 2;
    return b;
}
当该方法返回并弹出包含
b
的堆栈帧时,它所占用的内存将自动恢复。不涉及垃圾收集器

在这种情况下

public class Core {

    int b;

    public int addToA(int a) {
        b = a + 2;
        return b;
    }
}
public int addToA(int a) {
    int b = a + 2;
    return b;
}
b
将在为
核心
对象保留的堆空间中分配。只有在收集了
Core
后,才会对其进行垃圾收集

假设多次调用addToA方法,您是否保存 垃圾收集器通过使用第二个 一个

据我所知,你不会得到任何东西


请阅读文章,了解何时执行和何时不执行建议的示例。

局部变量始终在堆栈上声明(因此不要与类成员混淆,它们在堆上)。垃圾收集器是负责堆内存的工具。所以两者完全不同。堆栈上的变量将随着作用域的离开而弹出(例如:返回的方法)。

在您的示例中,
b
将在堆栈上,而不是在堆中,因此当堆栈帧弹出时,它将被回收。总承包商没有任何节约。这适用于方法中的所有局部变量

如果您分配了一个对象,而不仅仅是一个变量,那么就会涉及堆。因为您分配的
b
值是一个原语,所以在这里不起作用

但例如,假设是:

public class Core {

    int b;

    public int addToA(int a) {
        b = a + 2;
        return b;
    }
}
现在,堆栈上有一个变量,它保存对堆中对象的引用。从理论上讲,您可以通过重用其中一个来节省GC工作(以更高的内存使用为代价)。但是您必须重用
StringBuilder
,而不是变量。实际上,将对象重置为空白状态所需的努力、复杂性和(再次)更高的持续内存使用可能会抵消任何节省


(请注意,有些JVM可能会做一些您可能会干扰的聪明事情,比如将对象放在堆栈上,并将它们移动到堆中,如果方法调用终止后仍然存在对对象的引用。我知道V8在JavaScript世界中就是这样做的,V8从Sun的JVM中获得了很多灵感,所以……)
javap-vcore
救命

现场版本分解为:

StringBuilder sb = new StringBuilder();
 0: aload_0
 1: iload_1
 2: iconst_2
 3: iadd
 4: putfield      #2                  // Field b:I
 7: aload_0
 8: getfield      #2                  // Field b:I
11: ireturn
局部变量版本分解为:

StringBuilder sb = new StringBuilder();
 0: aload_0
 1: iload_1
 2: iconst_2
 3: iadd
 4: putfield      #2                  // Field b:I
 7: aload_0
 8: getfield      #2                  // Field b:I
11: ireturn
纯英语的局部变量版本:

  • 从局部变量1加载一个int值
  • 将int值2加载到堆栈中
  • 添加在步骤1和2加载的
    ints
  • 将int值存储到变量2中
  • 从局部变量2加载一个int值
  • 从方法返回一个整数

  • addToA
    调用期间没有执行堆内存分配。一切都是在堆栈上完成的。垃圾收集器停止。

    否,
    b
    将在堆栈上分配,当方法返回时,堆栈帧弹出时,内存将被清除。@SotiriosDelimanolis:这是一个答案,不是注释。:-)@T.J.Crowder我对这些细节不在行,我不想弄错什么。@SotiriosDelimanolis:看来你会得到足够的支持票,让它变得值得。你的不存在的答案得到了我精神上的支持票。可能有人怀有恶意,例如,如果他们不喜欢你在其他地方的评论。不幸的是,它发生了。