【问题标题】:How much space does an array occupy?一个数组占用多少空间?
【发布时间】:2012-07-13 08:10:11
【问题描述】:

如果我创建 10 个整数和一个 10 的整数数组,占用的总空间会有什么不同吗?

我必须创建一个包含数百万条记录的布尔数组,所以我想了解数组本身将占用多少空间。

【问题讨论】:

  • 是的,数组是一个对象,所以它不仅仅是值。该数组将占用更多空间。
  • 可能,但值得您花时间考虑这个问题吗?
  • 我想知道,如果我正在创建一个包含数百万条记录的布尔数组,数组将占用多少空间

标签: java arrays


【解决方案1】:

整数数组表示为用于保存整数的内存块和对象头。对于 32 位 JVM,对象标头通常需要 3 个 32 位字,但这取决于平台。 (标头包含一些标志位、对类描述符的引用、原始锁信息的空间以及实际数组的长度。加上填充。)

所以一个 10 个整数的数组可能占用13 * 4 字节的区域。

Integer[] 的情况下,每个 Integer 对象都有一个 2 字标题和一个包含实际值的 1 字字段。您还需要添加填充和 1 个字(或 64 位 JVM 上的 1 到 2 个字)以供参考。这通常是数组的每个元素 5 个字或 20 个字节......除非某些 Integer 对象出现在数组的多个位置。


注意事项:

  1. 在 64 位 JVM 上实际用于引用的字数取决于是否使用“压缩 oops”。
  2. 在某些 JVM 上,堆节点以 16 字节的倍数分配......这会增加空间使用量(例如上面提到的填充)。
  3. 如果您获取对象的标识哈希码并且它在下一次垃圾回收中幸存下来,则其大小会膨胀至少 4 个字节以缓存哈希码值。
  4. 除了上面列举的可变性来源之外,这些数字都是特定于版本和供应商的。

【讨论】:

  • 另外,每个指向这些对象的指针都需要四个(或 64 位 JVM 上的八个)。
  • @Thilo 实际上预测指针大小并不容易。由于对齐,JVM 仍然可以使用 4 字节指针。这就是我在系统中观察到的。
  • @MarkoTopolnik:太好了!我有点担心,当我当时检查时,我得到的答案是指针确实需要 8 个字节,除非你启用一些额外的压缩选项。 stackoverflow.com/questions/3733215/… 很高兴看到它现在已修复(似乎有点过分)。
  • @Thil0 - 我已经包含了那个...... “和一个单词供参考”
【解决方案2】:

一些粗略的下界计算:

每个 int 占用四个字节。 = 10 个字节 40 个字节

一个 int 数组为每个组件占用四个字节加上四个字节来存储长度加上另外四个字节来存储对它的引用。 = 48 字节(+ 可能有一些填充以将所有对象对齐在 8 字节边界)

一个整数至少占用 8 个字节,再加上另外 4 个字节来存储对它的引用。 = 十个至少 120

一个整数数组至少占用十个整数的 120 个字节加上四个字节的长度,然后可能需要一些填充来对齐。加上四个字节来存储对它的引用。 (@Marko 报告说他甚至测量了每个插槽大约 28 个字节,因此对于 10 个数组来说,这将是 280 个字节。

【讨论】:

  • 在 64 位 Java 上,所有指针占用 8 个字节而不是 4 个字节,这使得原始和包装器之间的差异更大。
  • 我测量过,一个充满 Integer 实例的Integer[] 平均每个插槽占用 28 个字节(64 位 JVM)。一个有趣的事实是,它与 Objects 的数组完全相同。
【解决方案3】:

在 java 中,你有 Integer 和 int。假设您指的是 int ,一个 int 数组被认为是一个对象,并且对象具有元数据,因此 10 个 int 的数组将占用超过 10 个 int 变量

【讨论】:

    【解决方案4】:

    根据您的评论,如果您使用数组,则不会有太大的不同。 Array 将为其功能本身使用可忽略不计的内存量。所有其他内存将由存储的对象使用。

    编辑:您需要了解的是布尔包装器和布尔原始类型之间的区别。包装类型通常会比原语占用更多的空间。因此,对于记录任务,请尝试使用原语。

    如您所说,在处理记录任务时要记住的另一件事是 Java 自动装箱。如果您无意中在遍历整个数组的函数中使用它,性能损失可能会很大。

    【讨论】:

    • 不过,如果是 Integer[]int[],差异可能会很大。在这种情况下,包装对象会占用大部分空间。
    • 同意。答案已编辑。但是 Array 语义将占用我认为的相同内存。主要区别来自存储在数组中的对象/元素。所以我认为我没有那么离谱。
    • 包装器类型参数很好,但是Boolean没那么多,因为可能的值只有两个,所以会有很多指针共享。当然,您仍然需要为引用存储四个(或八个)字节,而不是“只”一个用于布尔值。
    • 是的,不多,但仍然足以在大量记录中产生影响..
    【解决方案5】:

    你可以做的是测量

    public static void main(String[] args) {
      final long startMem = measure();
      final boolean[] bs = new boolean[1000000];
      System.out.println(measure() - startMem);
      bs.hashCode();
    }
    private static long measure() {
      final Runtime rt = Runtime.getRuntime();
      rt.gc();
      try { Thread.sleep(20); } catch (InterruptedException e) {}
      rt.gc();
      return rt.totalMemory() - rt.freeMemory();
    }
    

    当然,这与标准免责声明相一致:gc() 没有特别的保证,因此请重复几次以查看是否获得一致的结果。在我的机器上,答案是每个 boolean 一个字节。

    【讨论】:

    • 如果我想测量,我会使用 jmap 并查看堆内存转储。
    • @Thilo 如果您有一个已经在运行的系统,那将是您的最佳选择,但在这种情况下,这只是挖掘转储的额外工作。
    • @Thilo 这个方法我已经有很多经验了,而且准确率很高。
    • @Thilo 为了完整起见,我刚刚检查了转储方法。添加报告的分配大小时,它报告了 64 MB 的占用,但占用了 56MB 的总堆。不同之处在于它在一个对象数组中报告了 8 字节/槽,而实际上它是 4 字节/槽。我肯定会坚持我的方法:-)
    【解决方案6】:

    不必对老师/面试官造成不良影响。

    您对内存中变量的大小和对齐方式的关注程度取决于您对代码的性能要求。例如,如果您的软件处理交易(电子转帐/股票市场),这很重要。

    内存中变量的大小、对齐方式和打包可能会影响 CPU 缓存命中/未命中,这可能会影响代码性能高达 100 倍。

    只要您负责任地使用性能提升技巧,了解低级别发生的事情并不是一件坏事。

    例如,我来到这个线程是因为我需要确切地知道这个问题的答案,以便我可以调整我的基元数组的大小以填充 CPU 缓存行的整数倍,因为我需要执行计算的代码在这些原语数组上快速执行,因为我有一个有限的窗口,我需要在其中为结果的使用者做好计算准备。

    【讨论】:

      【解决方案7】:

      就RAM空间而言,没有真正的区别

      【讨论】:

      • 错误答案。检查 cmets 和其他答案。
      • +1 存在很大的相对差异,但除非您这样做 alot,否则它不会对您的应用程序产生真正的影响。
      【解决方案8】:

      如果你使用一个数组,你有 11 个对象、10 个整数和数组,而且数组里面还有其他元数据。所以使用数组会占用更多的内存空间。

      现在是真的。这种问题实际上出现在工作面试和考试中,这表明你有什么样的面试官或老师......在虚拟机和操作系统本身中有这么多抽象层,有什么意义在思考这个东西?微优化内存...!

      【讨论】:

      • 如果它是原始的int[],它只能是1个对象(这个问题有点不清楚)
      【解决方案9】:

      我的意思是如果我创建 10 个整数和 10 的整数数组,会有 占用的总空间有任何差异。

      (integer array of 10) = (10 integers) + 1 integer
      

      最后一个“+1整数”是数组的索引(数组可以容纳2,147,483,647个数据量,是一个整数)。这意味着当你声明一个数组时,说:

      int[] nums = new int[10];
      

      您实际上从内存中保留了 11 个 int 空间。数组元素为 10,数组本身为 +1。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多