我想再次学习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
堆栈 - 为主要功能占用一些内存
HEAP - 空的
## int b = 3
堆栈 - [为主要功能占用一些内存 - >这里我们有b]
HEAP - [空]
## TestA obj = new TestA()
堆栈 - [为主要功能占用一些内存 - >这里我们有b和对TestA的引用]
HEAP - [为int a记忆]
## obj.methodA(b);
堆栈 - [为主要功能占用一些内存 - >这里我们有b和对TestA的引用]
HEAP - [为int a取一些内存]和[methodA的另一个内存]
## execute methodA(int b)
STACK - [为主函数占用一些内存 - >这里我们有b和对TestA的引用]和[占用methodA()的内存 - >这里我们在这个函数中使用了b]
HEAP - [为int a取一些内存]和[methodA的另一个内存]
我们有:
-
对象和实例字段(原始与否)在堆中
-
堆栈中的函数和作用域值
这样对吗?
3 回答
在开始时,请记住堆也将为您的类(以及其他几个)提供
Class
实例 .回覆:
a
将在堆中,而不是在堆栈上,作为为TestA
实例分配的内存的一部分 .b
和obj
在堆栈上,在进入main
时分配(呃,我认为's when that happens; it could be that the JVM doesn' t为它们保留堆栈空间,直到它遇到程序流中的声明,但是我们进入了JVM的内部) . 堆还包含TestA
的实例 . (请记住,变量obj
与它指向[TestA
]的实例完全不同;每个事物都需要记忆 . )还要记住,堆栈将包含函数调用的返回地址 . 例如,当
main
调用methodA
时,当methodA
返回时JVM应该返回的地址也在堆栈上 .还将为异常处理分配各种堆栈结构 .
以上主要是理论上的,头脑 . 欢迎使用JVM进行优化,他们也做了(HotSpot是一个彻底优化的JVM) . 例如,@ Voo指出,如果JVM可以检测到它们可以将对象放在堆栈上(例如,当对象实例仅在方法中使用并且JVM的字节码分析表明它不可能存在时)当方法退出时,它是一个杰出的参考) .
尽管Java被指定为堆栈计算机,但实际上并没有以这种方式实现,因此在实际的JVM中,堆栈的大小仅在退出或进入方法时才会更改 .
堆永远不会为空 - 它包括像
Object.class
这样的对象,这些对象在main
启动之前由引导类加载器实例化 .所有操作如
new ClassName(...)
在堆*中分配空间,并且所有变量声明(int x
,Object ref
)指定在输入封闭函数时应在堆栈上留出空间** .** - 再次优化可以导致共享堆栈槽 .
默认情况下,所有对象都在堆上分配 . 但是,有编译器优化允许在堆栈上分配对象(或避免一起分配) . 特别是转义分析允许在java 6中使用它 .