我正在使用512GB RAM(由多个AMD Opteron 6212 CPU处理)的单台机器上工作。目前大约有300GB RAM免费。通过运行
运行大型Java计算java path/to/myApp -Xms280g -Xmx280g > output.txt
应该使Java立即保留280GB,如果失败则会出错。奇怪的是,没有发生错误,但top
仅显示30.4GB的内存使用量,但它不会崩溃。怎么会发生这种情况?如果无法分配初始堆大小,是不是java应该崩溃?
实际上,一旦30.4GB已满,我就会在达到280GB之前获得OutOfMemory / Java堆空间/ GC开销限制错误。使用250GB或300GB运行会产生类似的30.3GB~30.4GB限制。我在Gentoo Linux上运行带有OpenJDK运行时环境(IcedTea6)的OpenJDK 64位服务器虚拟机,并且有足够的可用内存(超过300GB)。
答案 0 :(得分:14)
参数的顺序不正确。您将-Xms280g -Xmx280g
作为参数传递给您自己的程序而不是JVM。正确的是:
java -Xms280g -Xmx280g path/to/myApp
答案 1 :(得分:2)
如果您希望在应用程序初始化期间抓取-Xms中指定的内存,请使用
java -XX:+ AlwaysPreTouch -Xms2G -Xmx2G ......
AlwaysPreTouch将在JVM初始化期间要求每个内存页面,而不是仅仅将不需要的内容保存为“虚拟”。但请注意,这在JVM启动时会有一些延迟。
使用上述开关,然后用顶部检查。您的JVM将获得完整的2G(实际上更多)。
答案 2 :(得分:0)
尝试在cmdline中添加-d64参数
java -d64 path/to/myApp -Xms280g -Xmx280g > output.txt
答案 3 :(得分:0)
所以你达到了大约32 GB的限制。虽然Oracle谈论Compressed oops in the Hotspot JVM
,但它也说约32GB。
但是,在LP64系统上,任何给定运行的堆可能必须大约是相应ILP32系统的1.5倍(假设运行适合两种模式)。这是由于托管指针的扩展大小。内存非常便宜,但是现在带宽和缓存供不应求,所以只是为了超过4Gb限制而大大增加堆的大小是痛苦的。
(另外,在x86芯片上,ILP32模式提供了LP64模式的一半可用寄存器.SPARC不会受到这种影响; RISC芯片从大量寄存器开始,只是为LP64模式加宽它们。)
压缩的oops表示托管指针(在JVM中的许多但不是所有位置)作为32位值,必须按8倍缩放并添加到64位基址以查找它们引用的对象。这允许应用程序处理多达40亿个对象(而不是字节),or a heap size of up to about 32Gb.