JVM将原始变量存储在哪里?

27

Java JVM把基本变量存储在何处,如何释放基本变量使用后的内存?

我猜应该是存在栈上吧?

3个回答

46
简单来说,这取决于变量声明的位置,而不是它的类型。
局部变量存储在栈上。实例变量和静态变量存储在堆上。
不要忘记,对于引用类型变量,变量的值是一个引用,而不是对象本身。(数组也是引用类型 - 因此如果你有一个 int[],其值将存储在堆上。)
现在,这可能是一个过于简单化的答案,因为聪明的虚拟机可以检测到特定引用类型变量是否指向一个永远“不会逃出”当前方法的对象。如果是这样,它可能会整个对象都内联到栈上。
但从概念上讲,这种模型是准确的。所以,一个被声明为实例变量的int类型的变量,像这样:
class Foo
{
    private int value;
    ...
}

这个变量在概念上将存在于堆中,作为任何Foo实例数据的一部分。它将随着释放实例而被释放 - 它只是表示Foo实例的数据块中的4个字节;它不需要单独的内存释放。


1
@JRomio:所有本地变量都是内置类型或句柄(Java 称之为引用,但本质上是指针),指向用户定义的类型,两者都是原始类型。只有所指向的 UDT 是非原始类型,但这与持有句柄的变量是不同的。 - Ben Voigt
虽然数组元素肯定是引用类型中的内容,但将数组元素称为“实例或静态变量”有些牵强,不是吗? - Ben Voigt
2
@Ben:在这种情况下,我根本不会称其为变量。我并没有说堆中的所有内容都是实例或静态变量。无论如何,经过澄清后肯定更好,所以谢谢 :) @Rakesh:是的,数组是引用类型。你是否认为每次执行赋值操作时都会复制数组的整个内容? - Jon Skeet
Java也会缓存一些整数。在这种情况下,Foo中的int会指向该缓存,并且永远不会被释放吗?还是这些缓存对象仅用于堆栈本地实例? - Sid
@Sid:你是指“整数”吗?“int”被缓存的想法是没有意义的...它只是4字节的值...它不是一个对象。 - Jon Skeet
显示剩余3条评论

9

变量存储的位置取决于变量是局部变量还是实例变量

局部变量存储在堆栈中。实例静态变量存储在中。

让我用一个例子来解释。假设我们有一个自定义类Animal的实例变量animal。 Animal animal = new Dog(); 这里,animal只是一个引用,并位于堆栈上。实际对象分配在上。该引用animal将指向在堆上分配的此对象内存。因此,如果您有3个引用指向同一对象。

Animal animal1 = new Dog();
Animal animal2 = new Dog();
Animal animal3 = new Dog();

所有三个引用将存储在堆栈中。当我提到引用时,它只是指向堆上对象的指针。就内存而言,此引用保存了对象在堆上的地址(实际上这里还有一些抽象)。因此,在32位和64位系统上,此引用占用4字节和8字节。只有当所有三个引用都被取消引用即不再在作用域内(或者说不再指向原始对象)时,垃圾回收器才可以释放分配给堆上对象的内存。

当我们存储基本类型或字符串常量时,会有一些微小的变化。除非你使用new()运算符显式地创建它们的对象,否则它们将在堆的permGen区域中创建和存储。因此,firstString和secondString两个引用都指向同一字符串,该字符串存储在permGen区域中。

String firstString = "Stack";
String secondString = "Stack";

相同的字符串字面量指向String池中的同一个对象。如果我们使用new()来创建字符串,那么就会指向不同的对象。


谈到Dog对象时犯了一个小错误。有三个不同的对象由三个不同的Animal引用指向。 - asgs

6
  • 类对象,包括方法代码和静态字段:堆。
  • 对象,包括实例字段:堆。
  • 局部变量和方法调用:栈。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接