Java 堆比预期的小

Java heap smaller than expected

我的一个主要项目有一些堆大小问题,我已解决。我决定试验一下我修复它的方式。我运行以下用java -jar <jarfile> -Xmx5G -Xms4G。 (初始 4GB,最大 5GB)。

int i = 0;

try {
    StringBuilder sb = new StringBuilder();

    for(i = 0; i < Integer.MAX_VALUE; i++) {
        sb.append('0');
    }
} catch (OutOfMemoryError e) {
    System.out.println("At: " + i);
    e.printStackTrace();
}

哪个打印的

At: 603979774
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.lang.AbstractStringBuilder.expandCapacity(Unknown Source)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(Unknown Source)
    at java.lang.AbstractStringBuilder.append(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)

为什么我的堆访问被限制为 576mb 的 2 个字节,当它被设置为至少 4gb 时?

您正在附加一个 2 个字节的 UNICODE 字符。你的迭代器 i 是 600M。因此,您分配了大约 1.2GB 的内存。

在 32 位 JVM 上,您可以在堆上分配的理论大小为 4GB。但这不太可能,因为还有其他因素在起作用(交换、内核、碎片),O/S 你是 运行 占用内存,JVM 占用内存,应用程序是 运行 占用内存、设备驱动程序、服务等。您不会获得整个 4GB 的理论堆 (2^32)。如果我记得,如果你 运行 在 32 位 Windows 上使用 32 位 JVM,则限制在 1.2GB 左右。

我认为其他答案忘记了一个重点。

代码在尝试将 StringBuilder 中的原始数组复制到另一个数组 (double the size from the original one) 时崩溃。

在这种情况下

  1. 原始数组的大小 ~ 1.2GB
  2. 新数组的大小 ~ 2.4GB

此时 JVM 将无法在新一代内存池中容纳新数组并崩溃。