【问题标题】:Is a Java array of primitives stored in stack or heap?Java 基元数组是存储在堆栈还是堆中?
【发布时间】:2015-05-03 01:48:40
【问题描述】:

我有一个这样的数组声明:

int a[];

这里的a 是一个原始int 类型的数组。这个数组存储在哪里?它是存储在堆上还是栈上?这是一个原始类型int,所有原始类型都不存储在堆上。

【问题讨论】:

  • 那不是数组。它是对数组的引用。如果引用本身是类或对象的成员,则引用本身可以存储在堆中,如果它是方法中的局部变量,则可以存储在堆栈中。如果原始类型是类或对象的成员,则它们可以存储在堆中。

标签: java arrays heap-memory primitive-types stack-memory


【解决方案1】:

它将存储在堆

因为数组是java中的对象。

编辑:如果你有

int [] testScores; 
testScores = new int[4];

将此代码想象为对编译器说:“创建一个包含四个整数的数组对象,并将其分配给名为 testScores 的引用变量。此外,继续将每个 int 元素设置为零。谢谢。”

【讨论】:

  • 并且名为testScores的引用变量(指向堆上的数组)会在栈上。
  • 如果您向编译器提供 -g 选项,代码只会说“谢谢”。否则它将被优化掉。
  • @mob 您假设这是唯一的代码。最好假设这两行是实际使用数组的更大程序的一部分。
【解决方案2】:

在 Java 编程语言中,数组是对象,是动态创建的,并且可以分配给 Object 类型的变量。

http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html

【讨论】:

    【解决方案3】:

    它是一个原始类型数组,其本身不是原始类型。一个好的经验法则是,当涉及新关键字时,结果将在堆上。

    【讨论】:

      【解决方案4】:

      正如 gurukulki 所说,它存储在堆上。但是,您的帖子暗示了一个误解,可能是由于一些善意的人传播了“原始人总是生活在堆栈上”的神话。这是不真实的。 局部变量在栈上有它们的值,但并不是所有的原始变量都是局部的……

      例如,考虑一下:

      public class Foo
      {
          int value;
      }
      ...
      
      public void someOtherMethod()
      {
          Foo f = new Foo();
          ...
      }
      

      现在,f.value 住在哪里?神话表明它在堆栈上——但实际上它是新的Foo 对象的一部分,并且存在于堆1 上。 (注意f 的值本身就是一个引用,并且存在于堆栈中。)

      从那里开始,数组是一个简单的步骤。你可以把数组想象成很多变量——所以new int[3] 有点像拥有这种形式的类:

      public class ArrayInt3
      {
          public readonly int length = 3;
          public int value0;
          public int value1;
          public int value2;
      }
      

      1 其实比这更复杂。堆栈/堆的区别主要是实现细节 - 我相信一些 JVM,可能是实验性的,可以判断对象何时永远不会从方法中“逃脱”,并且可以在堆栈上分配整个对象。但是,如果您选择关心,它在概念上在堆上。

      【讨论】:

      • 关于 Java 中的“转义分析”:blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead 它说它从 JDK 6 Update 14 的早期访问版本开始就存在,并且从 JDK 6 Update 23 开始默认启用。
      • 如果数组是 public static final,它会改变什么吗?那么它不应该是常量池的一部分吗?
      • @Malachiasz:不。数组永远不是常数。
      • @JonSkeet:在我知道的所有 Java 库版本中,每个 String 都由 char[] 支持。我相信文字字符串存储在公共常量池中;对于 GC 优化,这意味着应该同样存储后备数组(否则必须在后备数组有资格收集的任何 GC 周期期间扫描常量池)。
      • @supercat:是的,这是有道理的。但是你声明你自己的任何数组永远不会成为常量池的一部分。
      【解决方案5】:

      我只是想分享一些我在这个主题上运行的测试。

      大小为 1000 万的数组

      public static void main(String[] args) {
          memInfo();
          double a[] = new double[10000000];
          memInfo();
      }
      

      输出:

      ------------------------
      max mem = 130.0 MB
      total mem = 85.0 MB
      free mem = 83.6 MB
      used mem = 1.4 MB
      ------------------------
      ------------------------
      max mem = 130.0 MB
      total mem = 130.0 MB
      free mem = 48.9 MB
      used mem = 81.1 MB
      ------------------------
      

      如您所见,使用的堆大小增加了约 80 MB,即 10m * sizeof(double)。

      但是如果我们使用 Double 而不是 double

      public static void main(String[] args) {
          memInfo();
          Double a[] = new Double[10000000];
          memInfo();
      }
      

      输出将显示 40MB。我们只有双重引用,它们没有被初始化。

      用 Double 填充它

      public static void main(String[] args) {
          memInfo();
          Double a[] = new Double[10000000];      
          Double qq = 3.1d;
          for (int i = 0; i < a.length; i++) {
              a[i] = qq;
          }
          memInfo();
      }
      

      仍然是 40MB。因为它们都指向同一个 Double 对象。

      用 double 代替初始化

      public static void main(String[] args) {
          memInfo();
          Double a[] = new Double[10000000];
          Double qq = 3.1d;
          for (int i = 0; i < a.length; i++) {
              a[i] = qq.doubleValue();
          }
          memInfo();
      }
      
      Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
      

      线

      a[i] = qq.doubleValue();
      

      等价于

      a[i] = Double.valueOf(qq.doubleValue());
      

      相当于

      a[i] = new Double(qq.doubleValue());
      

      由于我们每次都创建新的 Double 对象,因此我们会炸毁堆。 这表明 Double 类中的值存储在堆中。

      【讨论】:

      • 你能粘贴 memInfo() 的代码细节吗? :)
      猜你喜欢
      • 2021-06-19
      • 1970-01-01
      • 2011-08-25
      • 2011-04-08
      • 2018-02-04
      • 2020-01-10
      • 2013-03-07
      • 2016-09-08
      相关资源
      最近更新 更多