假设我们在讨论一个基于32位OpenJDK的JVM。
- 每个Integer对象有1个int字段 - 占用4个字节。
- 每个Integer对象有2个标头字 - 占用8个字节。
- 分配的粒度是(我相信)2个字 - 4个字节的填充。
- Integer[]每个数组元素/位置都有1个引用 - 4个字节。
因此,每个数组元素总共有20个字节。20 x 30 x 1,000,000 = 600,000,000 Mbytes。现在加上代收集器将分配至少3个不同大小的对象空间,这可能会轻松增加到900多Mbyte。
如何修复它?
- 使用 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头部单词 - 8字节
- MyInt.bytes字段 - 4字节
- 填充 - 4字节
- 字节数组的头部单词 - 12字节
- 数组内容 - 4字节
现在加上MyInt引用所占的空间:
- 每个MyInt的引用 - 4字节
总计 - MyInt[]的每个元素占用36字节。
与Integer[]的20字节或int[]的4字节相比,这是一个很大的差距。
如何修复这种情况?
嗯,一个包含4字节的数组包含32位的数据。 这可以编码为int。因此修复方法与之前相同。 使用int[]而不是MyInt [],或者(可能)调整上面讨论的其他想法之一。
另外,可以增加堆大小,或使用数据库或类似的东西,使数据不需要保存在RAM中。