我只知道非基元(对象)进入堆,方法进入堆栈,但原始变量呢?
- 更新
根据答案,我可以说堆可以有一个新的堆栈和给定对象的堆?鉴于该对象将具有原始和引用变量..?
答案 0 :(得分:84)
本地定义的基元将在堆栈中。但是,如果将基元定义为对象实例的一部分,则该基元将位于堆上。
public class Test {
private static class HeapClass {
public int y; // When an instance of HeapClass is allocated, this will be on the heap.
}
public static void main(String[] args) {
int x=1; // This is on the stack.
}
}
关于更新:
对象没有自己的堆栈。在我的示例中,int y
实际上是HeapClass
的每个实例的一部分。每当分配一个HeapClass实例(例如new Test.HeapClass()
)时,HeapClass的所有成员变量都会被添加到堆中。因此,由于HeapClass
的实例正在堆上分配,int y
将作为HeapClass
实例的一部分在堆上。
但是,在任何方法的主体中声明的所有原始变量都是 在堆栈上 。
正如您在上面的示例中所看到的,int x
位于堆栈上,因为它在方法体中声明 - 而不是作为类的成员。
答案 1 :(得分:19)
所有局部变量(包括方法参数)都在堆栈中;对象及其所有字段都存储在堆中。变量总是基元或引用到对象。
Java实现实际上可以在堆上存储对象,使其仍然符合规范。类似地,局部变量可以存储在寄存器中,或者通过优化变得模糊不清。
答案 2 :(得分:10)
原语可以在两个地方找到。
class Foo
{
public int x;
public static void Main()
{
int y = 3; // y is on the stack
Foo f = new Foo(); // f.x is probably on the heap
}
}
除非您构建JVM,否则您不应该非常关心。一个非常聪明的优化器可能会决定,因为f指向的Foo永远不会逃脱Main,并且永远不会传递给另一个函数,因此可以安全地将它分配到堆栈中。
关于更新:
堆栈和堆不能通过存储在它们中的内容来区分,而是为它们提供的操作。堆栈允许您以LIFO方式分配一块内存,除非已经取消分配所有比它更小的部分,否则无法解除分配。这方便地与调用堆栈的使用方式一致。你可以把任何东西放在堆栈上,只要你的函数返回时该东西可以消失。这是一种优化,因为它可以非常快速地从堆栈中分配和释放,因为它只支持以这种方式使用。如果需要,可以在实现中存储堆上的函数的所有局部变量。堆更灵活,因此使用起来更昂贵。如我所说,对象有堆栈和堆是不准确的,堆栈与堆的不同之处不在于它,而是可用的操作。
答案 3 :(得分:7)
原始值在堆栈上分配,除非它们是对象的字段,在这种情况下它们会在堆上。堆栈用于评估和执行,因此没有理由说具有原始字段的对象具有堆栈 - 它仍然被认为是堆的一部分。甚至Stack
对象也在堆上分配。