Java原语是在堆栈还是堆上?

Tom*_*ito 55 java heap stack

我只知道非基元(对象)进入堆,方法进入堆栈,但原始变量呢?

--update

根据答案,我可以说堆可以有一个新的堆栈和给定对象的堆?鉴于该对象将具有原始和引用变量..?

Jac*_*nds 87

本地定义的基元将在堆栈上.但是,如果将基元定义为对象实例的一部分,则该基元将位于堆上.

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.
    }
}
Run Code Online (Sandbox Code Playgroud)

关于更新:

对象没有自己的堆栈.在我的例子中,int y实际上是每个实例的一部分HeapClass.每当分配HeapClass的实例(例如new Test.HeapClass())时,HeapClass的所有成员变量都被添加到堆中.因此,由于HeapClass正在堆上分配的实例,int y将作为实例的一部分在堆上HeapClass.

但是,在任何方法的主体中声明的所有原始变量都将在堆栈上.

正如您在上面的示例中所看到的,int x它位于堆栈上,因为它是在方法体中声明的 - 而不是作为类的成员.

  • 如果您考虑一下,这是完全有道理的,因为局部变量的词法范围将决定何时需要将其从堆栈中删除。:-)。当一个对象准备好进入垃圾时间时,整个对象就必须消失。不过,我总是在处理类的静态成员时遇到麻烦。我不记得这些值去了哪里。假设 `int y` 是一个静态成员:-P (2认同)

Tom*_*ine 19

所有局部变量(包括方法参数)都在堆栈中; 对象及其所有字段都存储在堆中.变量始终是基元或对象的引用.

Java实现实际上可以以仍然符合规范的方式在堆上存储对象.类似地,局部变量可以存储在寄存器中或通过优化变得模糊.


Log*_*ldo 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
   } 
}
Run Code Online (Sandbox Code Playgroud)

除非您正在构建JVM,否则您不应该非常关心.一个非常聪明的优化器可能会决定,因为f指向永远不会逃脱Main的Foo,并且永远不会传递给另一个函数,因此可以安全地将它分配到堆栈上.

关于更新:

堆栈和堆不是通过存储在它们中的内容来区分,而是为它们提供的操作.堆栈允许您以LIFO方式分配一块内存,除非已经取消分配所有比它更小的部分,否则无法解除分配.这方便地与调用堆栈的使用方式一致.你可以把任何东西放在堆栈上,只要你的函数返回时该东西可以消失.这是一种优化,因为它可以非常快速地从堆栈中分配和释放,因为它只支持以这种方式使用.如果需要,可以在实现中存储堆上的函数的所有局部变量.堆更灵活,因此使用起来更昂贵.如上所述,说对象有堆栈和堆是不准确的.


Mar*_*ade 7

原始值在堆栈上分配,除非它们是对象的字段,在这种情况下它们在堆上.堆栈用于评估和执行,因此没有理由说具有原始字段的对象具有堆栈 - 它仍然被认为是堆的一部分.甚至Stack对象都在堆上分配.