int []和Integer []数组的内存占用

时间:2011-05-21 13:09:51

标签: java memory heap

我尝试创建一个整数数组(我尝试使用自己的对象,但同样的情况发生在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+并且粉碎。

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

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

我该怎么办?

5 个答案:

答案 0 :(得分:7)

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

如果空间有问题,你应该只使用原始的int。 Here is a very good SO answer that explains this topic in more detail

答案 1 :(得分:2)

让我们假设我们正在谈论最近的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多个字节。

  

我该怎么办?

  • 使用int[]代替Integer
  • 如果Integer值主要表示-128到+ 127范围内的数字,请使用Integer.valueOf(int)进行分配。 JLS保证以这种方式创建的Integer个对象将被共享。 (注意,当通过自动装箱创建Integer时,JLS规定使用valueOf。事实上,这个“修复”已经在你的例子中应用了。)
  • 如果您的Integer值主要来自较大但仍然很小的域,请考虑实施自己的缓存以共享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个字节

总计 - MyIntMyInt[]个元素36个字节。

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

答案 2 :(得分:0)

Integer是一个超过4个字节的对象。实施依赖还有多少。你真的需要Integer吗?唯一的好处是它可以是null。也许你可以使用“sentinal value”代替;比如说,-1或Integer.MIN_VALUE

答案 3 :(得分:0)

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

答案 4 :(得分:0)

这不是你想要的,但最佳解决方案是在这个简单的例子中使用函数而不是数组。

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

如果您有更实际的示例,可以使用其他优化措施。