java OOM创建2个十亿整数的数组

时间:2019-03-24 12:09:39

标签: java jvm out-of-memory jvm-arguments

我正在用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);
  }
}

据我所知,用于十亿个int数组的内存将是System.out.println(1000_000_000 * Integer.SIZE); 返回1,935,228,928,小于2GB。因此,我的程序总要求最多为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选项,为什么?

2 个答案:

答案 0 :(得分:3)

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

无论如何,让我们进入实际的调整短语。 4GB可能太大,将直接存储在旧一代中。因此,您需要增加旧发电机的尺寸。更改新发电机的设置可能会起作用,但这很...那么,您实际上是在关闭旧发电机。它可能会损害您的测试用例的其他部分。

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

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

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

注意:最好保留几十兆字节,因为JVM本身将需要内存才能运行。如果您的程序不如MVCE小,那么如果您不希望GC偶尔出现,您将需要留出更多空间。

答案 1 :(得分:2)

here相同的问题。

在默认情况下使用Parallel GC的JDK 8中,将10 GB的堆划分为6.67 GB的旧一代+ 3.33 GB的年轻一代。因此,没有足够的空间容纳两个连续的3.72 GB的块(10亿个四字节整数)。

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

java -XX:+UseG1GC -Xmx8g TestBigIntArraySize