比较
public class Core {
public int addToA(int a) {
int b = a + 2;
return b;
}
}
to
public class Core {
int b;
public int addToA(int a) {
b = a + 2;
return b;
}
}
假设addToA
方法被称为很多,您是否使用第二个方法可以保存垃圾收集器工作(并加快程序)?
局部变量分配在堆栈上。
在这种情况下
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;
}
}
b
将分配在保留的堆积空间中,用于Core
对象。它只有在收集Core
时才会收集垃圾。
假设addtoa方法被称为很多,您保存是否保存 使用第二个 一个?
据我所知,您什么都不会获得。
去阅读T.J.克劳德(Crowder)的社区Wiki帖子以何时以及何时不做您建议的事情。
在您的示例中, b
将在堆栈上,而不是在堆上,因此当堆栈框架弹出时,它将被回收。GC根本没有节省。对于方法中的所有局部变量都是如此。
如果您分配一个对象,而不仅仅是具有变量,则会参与其中。因为您要分配b
的值是原始的,所以在这里没有发挥作用。
但是,例如,假设是:
StringBuilder sb = new StringBuilder();
现在,您在堆栈上有一个变量,该变量在堆中具有对对象的引用。从理论上讲,您可以通过拥有您重复使用的一种来保存GC工作(以更高的内存使用)来保存GC工作。但是您必须重复使用 StringBuilder
,而不是变量。实际上,任何节省的可能性都可能会因将对象重置为空白,复杂性和(再次)较高的持续记忆使用所需的精力而被洗净。
(请注意,某些JVM可能会干扰您要干扰的聪明的事情,例如将对象放在堆栈上并将其移动到堆如果对对象的引用幸存下来方法调用。我知道V8在JavaScript世界中做到了,V8从Sun的JVM中获得了很多灵感,所以...)
javap -v Core
to Rescue!
字段版本分配为:
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
本地变量版本分解为:
0: iload_1
1: iconst_2
2: iadd
3: istore_2
4: iload_2
5: ireturn
普通英语的本地变量版本:
- 从局部变量1 加载int值
- 将int值2加载到堆栈
- 添加
ints
在步骤1和2
处加载 - 将int值存储到变量2 中
- 从局部变量2 加载int值
- 从方法返回整数
在addToA
调用期间没有执行堆内存分配。一切都在堆栈上完成。垃圾收集器休息。
局部变量始终在堆栈上声明(因此请勿与类成员混合,而是在堆上)。垃圾收集器是一种照顾堆内存的工具。所以两者都是完全不同的。堆栈上的变量将在剩余范围时弹出(例如:返回的方法)。