我正在尝试初始化一个大小为 10 位整数的布尔类型数组。它继续抛出OutOfMemoryException。我已将 Eclipse 的堆空间大小从 256 增加到 1024。有什么我想做的吗?
int size = 1000000000;
boolean[] primesList = new boolean[size];
我正在尝试初始化一个大小为 10 位整数的布尔类型数组。它继续抛出OutOfMemoryException。我已将 Eclipse 的堆空间大小从 256 增加到 1024。有什么我想做的吗?
int size = 1000000000;
boolean[] primesList = new boolean[size];
使用java.util.BitSetboolean
,与使用数组相比,它会将位打包在八分之一的空间中。
布尔数组元素占用 1 个字节而不是 1 位的原因是因为(大多数)CPU 架构不提供直接读取和写入单个内存位的能力。PC 可以操作的最小单位有 8 位。JVM可以将这些位打包在一起,然后修改一个位,它会读取字节,修改它,然后将其写回,但如果多个线程同时修改数组,这将不起作用。
至于您的原始数组,它是 10 亿个布尔值,每个一个字节,即 10 亿字节或 ~954 MB。所以一个 1024 MB 的堆应该足够了(?)。也许它找不到足够大的连续内存块,或者您没有正确设置内存参数。打印 的值Runtime.getRuntime().maxMemory()
以找出 Java 正在使用的最大堆大小。对于 1024 MB,参数应该是-Xmx1024M
.
最后注意事项:从 Java 7 开始,您可以在数字中使用下划线以使其更具可读性。所以你可以写1_000_000_000
而不是1000000000
.
来自文档
这种数据类型代表一点信息,但它的“大小”并不是精确定义的。
如果您认为布尔值至少有一个字节,则该1000000000
字节需要953MB
用于数组的内存。
所以这是唯一一个吃掉 的数组953MB
, 1024MB
可能会导致问题。
但在一个美好的世界里,我猜这个用例不需要:)
只需请求更多的堆大小,例如 -X1500M 绝对有效。您的数组占用 1000000000 个字节,但您需要请求更多,因为 Java 堆分为新老代。
启动 JVM 时,您需要传递 -Xmx 参数以将最大堆空间设置为更高。
另请注意,数组的最大大小为 Integer.MAX_VALUE
您可以改用对象持有者,避免一次分配所有空间的需要 - 如果堆大小足够大,这可能会解决问题。您需要大量空间来在数组中保存这么多布尔值 - 确保为堆空间设置了最小和最大大小。也可以使用 List 之类的东西来仅在需要时填写值。如果你真的需要它作为一个数组,有一些方法可以转换回来(apache commons 中的 Arrays 集合允许你使用 Arrays.toPrimitive)。
由于以下两个原因,它可能非常好:
根据这篇文章,JVM 不会将整个 Xmx 数量分配给您的程序。幸存者空间之一占用的空间被打折,因为 JVM 在内部将其用于一些簿记或临时使用。这可能是在这种情况下 1024 MB 不够的原因,因为您的阵列已经在使用 954 MB。幸存者空间可能超过 70 MB。如下所述,增加 Xmx 可能有帮助,也可能没有帮助
根据这篇文章,如果您的数据结构对于堆中的任何代(伊甸园、从/到幸存者、旧代)来说都太大,则可以使用 OOM。您可以使用 -XX:+PrintGCDetails 并查看每一代获得了多少。因此,您必须不断增加您的 Xmx,直到其中至少一个(eden、from/to、old gen)大到足以容纳您的对象,或者您必须明确设置不同堆区域的大小(例如,- XX:年轻一代的新尺寸)。