当我运行以下程序时(使用 "java -Xmx151M -cp .com.some.package.xmlfun.Main"
运行):
package com.some.package.xmlfun;
public class Main {
public static void main(String [] args) {
char [] chars = new char[50 * 1024 * 1024];
}
}
我需要将最大内存增加到至少 151M (-Xmx151M)。因此,当我增加数组大小时,需要增加限制:
- 50 * 1024 * 1024 -> -Xmx151M
- 100 * 1024 * 1024 -> -Xmx301M
- 150 * 1024 * 1024 -> -Xmx451M
为什么 java 看起来每个字符需要 3 个字节,而不是文档建议的 2 个字节?
另外,当我类似地创建 long 数组时,它似乎每个 long 需要 12 个字节,而不是 8 个字节,而 int 它需要 6 个字节而不是 4 个字节。通常看起来它需要 array_size * element_size * 1.5
编译- javac\com\som\package\xmlfun\\*java
使用 - java -Xmx151M -cp 运行。 com.some.package.xmlfun.Main
最佳答案
我想您所看到的可以很容易地通过 JVM 中堆的组织方式来解释。
当您将参数 -Xmx
传递给 JVM 时,您正在定义最大堆大小 应该是多少。但是,它与您可以分配的数组的最大大小没有直接关系。
在JVM中,垃圾收集器负责为对象分配内存,并负责清理死对象。垃圾收集器决定如何组织堆。
你通常有一个叫做伊甸园空间的东西,然后是两个幸存者空间,最后是终身一代。这些都在堆里面,GC把最大的堆分给他们。有关这些内存池的更多详细信息,请查看这个出色的答案:https://stackoverflow.com/a/1262474/150339
我不知道默认值是多少,它们可能确实取决于您的系统。我刚刚检查了(使用 sudo jmap PID
)内存池如何划分我在运行 Ubuntu 64 位和 Oracle Java 7 的系统上运行的应用程序中的堆。机器有 1.7GB 内存。
在该配置中,我只将-Xmx
传递给JVM,GC按如下方式划分堆:
- 大约 27% 用于伊甸园空间
- 每个幸存者空间约 3%
- 大约 67% 是老一代。
如果您有类似的分布,则意味着您的 151MB 中最大的连续 block 位于永久代中,大约为 100MB。由于数组是一个连续的内存块,而您根本无法让一个对象跨越多个内存池,它解释了您所看到的行为。
您可以尝试使用垃圾收集器参数。在此处检查垃圾收集器参数:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
你的结果对我来说似乎很合理。
关于Java char 数组似乎每个 char 需要超过 2 个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17344782/