【问题标题】:Memory footprint of int[] and Integer[] arraysint[] 和 Integer[] 数组的内存占用
【发布时间】:2011-08-30 05:32:58
【问题描述】:

我尝试创建一个整数数组(我尝试使用自己的对象,但使用 int 也是如此),大小为 3000 万。我不断收到“OutOfMemoryError:Java 堆空间”

Integer [] index = new Integer[30000000];
for (int i = 0 ; i < 30000000 ; i++){
    index[i] = i;
}

我使用“Runtime.getRuntime().totalMemory()”和“maxMemory()”检查了总堆空间 看到我从 64 MB 开始,最大值为 900+ MB,在运行期间我在堆上达到 900+ 并粉碎。

现在我知道 Integer 需要 4 个字节,所以即使我乘以 30*4*1000000,我仍然应该只得到大约 150-100 兆。

如果我尝试使用原始类型,例如 int,它可以工作。

我该如何解决?

【问题讨论】:

  • 用更多的堆内存运行程序。

标签: java memory heap-memory


【解决方案1】:

Integer 是一个占用超过 4 个字节的对象。还有多少取决于实现。你真的需要Integer吗?唯一的好处是它可以是null。也许您可以改用“sentinal value”;比如,-1,或Integer.MIN_VALUE

【讨论】:

    【解决方案2】:

    Java 的 int 原语将占用 4 个字节,但如果您使用像 Integer 这样的 ValueObject,它将占用更多空间。根据您的机器,单独的引用可能会占用 32 位或 64 位 + 它所包装的基元的大小。

    如果空间是一个问题,您可能应该只使用原始整数。 Here is a very good SO answer that explains this topic in more detail

    【讨论】:

    • 我相信他对 Integer 的使用仅用于演示目的。我相信真正的代码使用了一个非整数自定义类对象的数组。
    • 你是对的,我使用我自己的对象。我不明白它怎么会占用这么多空间
    • 是的,它是参考大小开销让你。如果你使用的是 Java 64bit,你也可以尝试 -XX:+UseCompressedOops 来帮助减少引用的大小。
    • CompressedOoops 会将Integer[] 数组的大小大致减半,但Integer 对象的大小保持不变。
    【解决方案3】:

    也许您应该使用数据库而不是大型数组,但如果您必须使用大型对象数组,您是否尝试过在运行 Java 应用程序启动器时使用 -Xms 命令行参数来增加 Java 内存大小?

    【讨论】:

      【解决方案4】:

      假设我们谈论的是最近的 32 位 Sun JVM。

      • 每个 Integer 对象都有 1 个int 字段 - 占用 4 个字节。
      • 每个 Integer 对象有 2 个标题字 - 占用 8 个字节。
      • 分配的粒度是(我相信)2 个字 - 4 个字节的填充。
      • Integer[] 对每个数组元素/位置都有 1 个引用 - 4 个字节。

      所以每个数组元素总共是 20 个字节。 20 x 30 x 1,000,000 = 600,000,000 MB。现在添加一个事实,即分代收集器将分配至少 3 个不同大小的对象空间,这很容易加起来达到 900+ MB。

      我该如何解决?

      • 使用int[] 而不是Integer
      • 如果Integer 值主要代表-128 到+ 127 范围内的数字,则使用Integer.valueOf(int) 分配它们。 JLS 保证以这种方式创建的Integer 对象将被共享。 (请注意,当 Integer 是通过自动装箱创建时,JLS 规定使用 valueOf。因此,实际上,此“修复”已应用于您的示例。)
      • 如果您的 Integer 值主要来自较大但仍然较小的域,请考虑实现自己的缓存以共享 Integer 对象。

      我的问题是以整数为例,在我的程序中,我使用自己的对象,该对象仅包含一个字节数组(最大大小为 4)。当我创建它时,它在内存上需要超过 4 个字节。

      是的,会的。

      假设你的类是这样定义的:

      public class MyInt {
          private byte[] bytes = new byte[4];
          ...
      }
      

      每个MyInt都会占用:

      • MyInt 标头字 - 8 个字节
      • MyInt.bytes 字段 - 4 字节
      • 填充 - 4 个字节
      • 字节数组的标题字 - 12 个字节
      • 数组内容 - 4 个字节

      现在添加MyInt 引用占用的空间:

      • 引用每个MyInt - 4 个字节

      总计 - MyInt[] 的每个 MyInt 元素 36 个字节。

      Integer[] 的每个 Integer 元素 20 个字节或 int[] 的每个 int 元素 4 个字节进行比较。

      【讨论】:

      • 我的问题是以整数为例,在我的程序中,我使用自己的对象,该对象仅包含一个字节数组(最大大小为 4)。当我创建它时,它会占用内存超过 4 个字节。
      【解决方案5】:

      这不是您要寻找的,但最佳解决方案是在此简单示例中使用函数而不是数组。

      static int index(int num) {
          return num;
      }
      

      如果您有更实际的示例,您可能还可以使用其他优化方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-21
        • 2012-08-15
        • 1970-01-01
        • 2013-04-28
        • 2012-05-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多