我想再次学习Java,因为我几年前就离开了。读一本书我在理解Java如何在堆中和堆栈中分配内存时遇到了问题。
这是我所理解的 - 我会尝试用例子来谈论它。
class TestA {
int a;
void methodA(int b) {
a = b;
}
int getA() {
return a;
}
}
这是一个展示不同情况的示例类。这是我的主要内容:
int b = 3;
TestA obj = new TestA();
obj.methodA(b);
obj.getA();
那会发生什么?
## BEGIN
STACK - 为主要功能
占用一些内存HEAP - 空
## int b = 3
堆叠 - [为主要功能占用一些内存 - >在这里我们有b]
HEAP - [空]
## TestA obj = new TestA()
堆叠 - [为主要功能占用一些内存 - >这里我们有b和对TestA的引用]
HEAP - [为int获取一些记忆]
## obj.methodA(b);
堆叠 - [为主要功能占用一些内存 - >这里我们有b和对TestA的引用]
HEAP - [为int a取一些内存]和[methodA的另一个内存]
##执行方法A(int b)
堆叠 - [为主要功能占用一些内存 - >这里我们有b和对TestA的引用]和[记忆方法A() - >这里我们在这个函数中使用了b]
HEAP - [为int a取一些内存]和[methodA的另一个内存]
我们有:
是不是?
答案 0 :(得分:2)
首先,请记住,堆也将为您的班级(以及其他几个)提供Class
个实例。
回复:
## TestA obj = new TestA()
堆叠 - [为主要功能占用一些内存 - >这里我们有b和对TestA的引用]
HEAP - [为int获取一些记忆]
a
将在堆中,而不是在堆栈上,作为为TestA
实例分配的内存的一部分。 b
和obj
在堆栈上,在进入main
时分配(呃,我认为发生这种情况时;可能是JVM没有为它们保留堆栈空间,直到它遇到了程序流中的声明,但是我们正在进入JVM的内部。堆还包含TestA
的实例。 (请记住,变量obj
与它指向[{1}}]的实例完全不同;每个事物都需要记忆。)
还要记住,堆栈将包含函数调用的返回地址。例如,当TestA
调用main
时,JVM在methodA
返回时应返回的地址也在堆栈中。
还将为异常处理分配各种堆栈结构。
以上主要是理论上的,心灵。欢迎使用JVM进行优化,他们也做了(HotSpot是一个彻底优化的JVM)。例如,@ Voo指出,如果JVM可以检测到它们可以将对象放在堆栈上(例如,当对象实例仅在方法中使用并且JVM的字节码分析表明它不可能存在时)当方法退出时,它是一个杰出的参考。
答案 1 :(得分:1)
尽管Java被指定为堆栈计算机,但实际上并没有以这种方式实现,因此在实际的JVM中,堆栈的大小只会在退出或进入方法时发生变化。
堆永远不会为空 - 它包含Object.class
等对象,这些对象在main
启动之前由引导类加载器实例化。
new ClassName(...)
等所有操作在堆*中分配空间,所有变量声明(int x
,Object ref
)指定在输入封闭函数时应在堆栈上留出空格**。
* - 请参阅有关https://stackoverflow.com/a/8690592/20394的优化的警告 ** - 再次优化可能导致共享堆栈槽。
答案 2 :(得分:0)
默认情况下,所有对象都在堆上分配。但是,有编译器优化允许在堆栈上分配对象(或避免一起分配)。特别是转义分析允许在java 6中使用它。