我尝试创建一个整数数组(我尝试使用自己的对象,但同样的情况发生在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,它就可以工作。
我该怎么办?
答案 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。
int
字段 - 占用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字节现在添加MyInt
引用所占用的空间:
MyInt
- 4个字节总计 - MyInt
每MyInt[]
个元素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;
}
如果您有更实际的示例,可以使用其他优化措施。