int[] 和 Integer[] 数组的内存占用
我尝试创建一个整数数组(我尝试使用自己的对象,但 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+ MB。
现在我知道 Integer 需要 4 个字节,所以即使我乘以 30*4*1000000 我仍然只能得到大约 150-100 兆。
如果我尝试使用原始类型,例如 int,它会起作用。
我该如何解决它?
I try to create an array of Integers (i tried with own object but the same happened with int) , with size of 30 million. i keep getting "OutOfMemoryError: Java heap space"
Integer [] index = new Integer[30000000];
for (int i = 0 ; i < 30000000 ; i++){
index[i] = i;
}
i checked the total heap space, using "Runtime.getRuntime().totalMemory()" and "maxMemory()"
and saw that i start with 64 MB and the max is 900+ MB, and during the run i get to 900+ on the heap and crush.
now i know that Integer takes 4 bytes, so even if i multiply 30*4*1000000 i should still only get about 150-100 mega.
if i try with a primitive type, like int, it works.
how could i fix it ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Java 的 int 原语将占用 4 个字节,但如果您使用像 Integer 这样的 ValueObject,它将占用更多空间。根据您的机器,单独的引用可能占用 32 或 64 位+它所包装的原语的大小。
如果空间是个问题,您可能应该只使用原始整数。
Java's int primitive will take up 4 bytes but if you use a ValueObject like Integer it's going to take up much more space. Depending on your machine a reference alone could take up 32 or 64 bits + the size of the primitive it is wrapping.
You should probably just use primitive ints if space is an issue. Here is a very good SO answer that explains this topic in more detail.
假设我们正在讨论基于 OpenJDK 的 32 位 JVM。
int
字段 - 占用 4 个字节。因此每个数组元素总计 20 个字节。 20 x 30 x 1,000,000 = 600,000,000 兆字节。现在添加一个事实,即分代收集器将分配至少 3 个不同大小的对象空间,并且可以轻松添加到 900+ MB。
int[]
而不是Integer
。Integer
值主要表示 -128 到 + 127 范围内的数字,请使用Integer.valueOf(int)
分配它们。 JLS 保证以这种方式创建的Integer
对象将被共享。 (请注意,当通过自动装箱创建Integer
时,JLS 规定使用valueOf
。因此,事实上,此“修复”已应用在您的例如。)Integer
值主要来自较大但仍然较小的域,请考虑实现您自己的缓存以共享Integer
对象。是的,会的。
假设您的类定义如下:
每个
MyInt
将占用:MyInt
标头字 - 8 字节MyInt.bytes
字段 - 4 字节现在添加
MyInt
引用占用的空间:MyInt
的引用 - 4 字节总计-
MyInt[]
的每个MyInt
元素 36 个字节。与
Integer[]
的每个Integer
元素 20 个字节或int[]
的每个int
元素 4 个字节进行比较代码>.如何解决这个问题?
一个 4 字节的数组包含 32 位数据。可以将其编码为
int
。所以修复方法与之前相同。使用int[]
而不是MyInt[]
,或者(可能)采用上面讨论的其他想法之一。或者,增大堆,或者使用数据库或类似的东西,这样数据就不需要保存在 RAM 中。
Lets assume that we are talking about a 32bit OpenJDK-based JVM.
int
field - occupying 4 bytes.So the total is 20 bytes per array element. 20 x 30 x 1,000,000 = 600,000,000 Mbytes. Now add the fact that the generational collector will allocate at least 3 object spaces of various sizes, and that could easily add up to 900+ Mbytes.
int[]
instead ofInteger
.Integer
values mostly represent numbers in the range -128 to + 127, allocate them withInteger.valueOf(int)
. The JLS guarantees thatInteger
objects created that way will be shared. (Note that when anInteger
is created by auto-boxing, then JLS stipulates thatvalueOf
is used. So, in fact, this "fix" has already been applied in your example.)Integer
values mostly come from a larger but still small domain, consider implementing your own cache for sharingInteger
objects.Yes, it will do.
Let's assume your class is defined like this:
Each
MyInt
will occupy:MyInt
header words - 8 bytesMyInt.bytes
field - 4 byteNow add the space taken by the
MyInt
reference:MyInt
- 4 bytesGrand total - 36 bytes per
MyInt
element of aMyInt[]
.Compare that with 20 bytes per
Integer
element of anInteger[]
or 4 bytes perint
element of anint[]
.How to fix that case?
Well an array of 4 bytes contains 32 bits of data. That can be encoded as
int
. So the fix is the same as before. Use anint[]
instead of aMyInt[]
, or (possibly) adapt one of the other ideas discussed above.Alternatively, make the heap larger, or use a database or something like that so that the data doesn't need to be held in RAM.
Integer
是一个占用超过 4 个字节的对象。还有多少取决于实施。你真的需要Integer
吗?唯一的好处是它可以为 null。也许你可以使用“哨兵值”来代替;例如,-1 或Integer.MIN_VALUE
。Integer
is an object which will take more than 4 bytes. How much more is implementation dependent. Do you really needInteger
? The only benefit is that it can benull
. Perhaps you could use a "sentinal value" instead; say, -1, orInteger.MIN_VALUE
.也许您应该使用数据库而不是大型数组,但如果您必须使用大型对象数组,您是否尝试在运行 Java 应用程序启动器时使用 -Xms 命令行参数来增加 Java 内存大小?
Perhaps you should be using a database rather than a huge array, but if you must use a huge array of objects, have you tried increasing the Java memory size by using a the -Xms command line argument when running the Java application launcher?
这不是您想要的,但最佳解决方案是在这个简单的示例中使用函数而不是数组。
如果您有更现实的示例,可能还可以使用其他优化。
This is not what you are looking for but the optimal solution is to use a function instead of an array in this simple example.
If you have a more realistic example, there may be other optimisations you can use.