java OOM 关于创建 2 个 10 亿个整数的数组



我正在用java编写简单的程序来创建2个10亿大小的int数组。 我用-Xms10G运行了这个程序,即10GB的内存仍然出现OOM错误。 下面是片段。

public class TestBigIntArraySize {
public static int arraySize = 1000_000_000;
public static int [] firstArray = new int[arraySize];
public static int [] secondArray = new int[arraySize];
public static void main(String[] args) {
System.out.println(1000_000_000 * Integer.SIZE);
}
}

据我所知,用于 10 亿个 int 数组的内存将是 System.out.println(1000_000_000 * Integer.SIZE); 返回小于 2GB 的 1,935,228,928。所以我的程序总要求最大为 4GB。

即使我在方法调用中创建数组并返回数组或静态(如下所示)或在 main() 中,我也会收到错误。 它工作所需的内存是 12G,是我预期的 3 倍。 我正在使用oracle java:jdk1.8.0_201

我尝试了选项 -Xms10G -XX:NewRatio=1 ---它有效。

但我想进一步减少我的内存占用。

我尝试通过-Xms9G -XX:NewRatio=0.5为伊甸园提供更多内存的选项,但java抱怨非法论点。

我尝试了通过-Xms9G -XX:NewRatio=1 -XX:PretenureSizeThreshold=10000直接将数组分配给旧世代的选项。但这也给了OOM。

这只是一个实验项目,我只是在操作数组。我想在尽可能小的内存中做到这一点。 有人可以建议如何去做吗?哪些 Java 选项,为什么?

因此,假设乘以位长度可能不是获取字节计数的最佳方式。正如@mayamar所提到的,您的实际内存使用量约为2 * 4 GB字节。

无论如何,让我们进入实际的调音短语。 4GB可能太大,将直接存储在旧一代中。所以你需要增加老一代的大小。更改新的生成设置可能会起作用,但那是...好吧,你实际上是在关闭旧一代。它可能会损害测试用例的其他部分。

您尝试NewRatio=1使新旧世代比例为 1:1,而不是更好的比例,例如 1:100。但是,如果比率太大,JVM可能无法启动(VM初始化期间的GC)。最好只用MaxNewSize指定它。

最后,运行与此类似的内容将非常接近您的"最小化内存占用"要求。

java -Xmx8400000000 -XX:MaxNewSize=30M -XX:OldSize=8300000000 TestBigIntArraySize 

注意:最好腾出几十兆字节,因为JVM本身需要内存才能运行。如果你的程序不像你的MVCE那么小,如果你不希望GC时不时地启动,你将需要留出更多的空间。

和这里一样的问题。

在默认使用并行 GC 的 JDK 8 中,10 GB 堆分为 6.67 GB 老一代 + 3.33 GB 年轻一代。因此,没有空间容纳两个 3.72 GB(10 亿个四字节整数)的连续块。

解决此问题的最简单方法是打开 G1 GC 并完全避免棘手的生成大小调整。然后,您的示例将使用 8 GB 堆:

java -XX:+UseG1GC -Xmx8g TestBigIntArraySize

最新更新