我只知道非原始(对象)在堆上,方法在堆栈上,但是原始变量呢?
- 更新
根据答案,我可以说堆可以有一个给定对象的新堆栈和堆?鉴于该对象将具有原始变量和引用变量..?
我只知道非原始(对象)在堆上,方法在堆栈上,但是原始变量呢?
- 更新
根据答案,我可以说堆可以有一个给定对象的新堆栈和堆?鉴于该对象将具有原始变量和引用变量..?
本地定义的原语将在堆栈上。但是,如果将原语定义为对象实例的一部分,则该原语将位于堆上。
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
它在堆栈上,因为它是在方法体中声明的——而不是作为类的成员。
所有局部变量(包括方法参数)都在堆栈上;对象及其所有字段都存储在堆中。变量始终是原语或对对象的引用。
Java 实现实际上可能以仍然符合规范的方式将对象存储在堆上。类似地,局部变量可以存储在寄存器中或通过优化变得模糊。
在这两个地方都可以找到原语。
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 方式分配一块内存,直到所有比它年轻的块也都被释放后,您才能释放一块内存。这方便地与调用堆栈的使用方式保持一致。您可以将任何东西放在堆栈上,只要在您的函数返回时该东西可以消失即可。这是一种优化,因为它只支持以这种方式使用,所以从堆栈中分配和解除分配非常快。如果愿意,可以在实现中将函数的所有局部变量存储在堆上。堆更灵活,因此使用成本更高。正如我所说,说一个对象有一个堆栈和一个堆是不准确的,
原始值在堆栈上分配,除非它们是对象的字段,在这种情况下它们会在堆上。堆栈用于评估和执行,所以说具有原始字段的对象有一个堆栈是没有意义的——它仍然被认为是堆的一部分。甚至Stack
对象也分配在堆上。