这个问题不是关于32位操作系统的最大堆大小,因为32位操作系统的可寻址内存大小最大为4GB,而JVM的最大堆大小取决于可以保留多少连续的空闲内存。
我更想知道在64位操作系统上运行的32位JVM的最大(理论和实际可达到)堆大小。基本上,我正在寻找类似于SO中相关问题答案中的数字的答案。
至于为什么使用32位JVM而不是64位JVM,原因不是技术上的,而是行政/官僚主义的 - 在生产环境中安装64位JVM可能为时已晚。
你可以询问Java运行时:
public class MaxMemory {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
long totalMem = rt.totalMemory();
long maxMem = rt.maxMemory();
long freeMem = rt.freeMemory();
double megs = 1048576.0;
System.out.println ("Total Memory: " + totalMem + " (" + (totalMem/megs) + " MiB)");
System.out.println ("Max Memory: " + maxMem + " (" + (maxMem/megs) + " MiB)");
System.out.println ("Free Memory: " + freeMem + " (" + (freeMem/megs) + " MiB)");
}
}
-Xmx
(在HotSpot上)。我发现在运行Windows 7企业版64位时,我的32位 HotSpot JVM可以分配高达1577MiB:
[C:scratch]> java -Xmx1600M MaxMemory VM初始化期间发生错误 无法为对象堆保留足够的空间 无法创建Java虚拟机。 [C:scratch]> java -Xmx1590M MaxMemory 总内存:2031616(1.9375 MiB) 最大内存:1654456320(1577.8125 MiB) 可用内存:1840872(1.75559234619 MiB) [C:scratch]>而在同一操作系统上使用64位 JVM,当然更高(约为3TiB)
[C:scratch]> java -Xmx3560G MaxMemory VM初始化期间发生错误 无法为对象堆保留足够的空间 [C:scratch]> java -Xmx3550G MaxMemory 总内存:94240768(89.875 MiB) 最大内存:3388252028928(3184151.84297 MiB) 可用内存:93747752(89.4048233032 MiB) [C:scratch]>正如其他人已经提到的那样,它取决于操作系统。
对于64位主机操作系统,如果JVM为32位,则仍将取决于上述演示的大多数情况。
-- 更新20110905:我只想指出一些其他的观察/细节:
Runtime.MaxMemory
实际可分配的最大内存也取决于操作系统的工作集。我曾经在同时运行VirtualBox时运行过这个程序,并发现我不能成功地使用-Xmx1590M
启动HotSpot JVM,只能减小内存设置。这也意味着,根据您在某一时刻的工作集大小,您可能会获得超过1590M的内存(尽管我仍然认为对于32位而言,由于Windows的设计,它将不会超过2GiB)32位的Java虚拟机只能使用单个大块内存并使用原始指针,因此不能超过4 Gb(这是32位限制,也适用于指针)。这包括Sun和我非常确定的IBM实现。我不知道例如JRockit或其他人是否具有其32位实现的大内存选项。
如果您预计会遇到此限制,强烈建议您启动并行轨道,为生产环境验证64位Java虚拟机,以便在32位环境崩溃时准备好该解决方案。否则,您将不得不在压力下完成这项工作,这是不好的。
编辑2014-05-15:Oracle FAQ:
32位JVM的最大理论堆限制为4G。由于各种附加约束条件,例如可用交换、内核地址空间使用、内存碎片和VM开销,实际上限制可能要低得多。在大多数现代32位Windows系统上,最大堆大小将在1.4G至1.6G之间。在32位Solaris内核上,地址空间限制为2G。在运行32位虚拟机的64位操作系统上,最大堆大小可以更高,在许多Solaris系统上接近4G。
(http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit)
-XX:+AlwaysPreTouch
,你所请求的是虚拟空间,一旦启用该键 - 它将失败。 - Eugene你没有说明是哪个操作系统。
在 Windows 下(对于我的应用程序 - 一个长期运行的风险管理应用程序),我们发现在 Windows 32 位上最多只能使用 1280MB。我怀疑在64位操作系统下运行 32 位 JVM 不会有任何不同。
我们将该应用程序移植到 Linux 并在64位硬件上运行32位 JVM,很容易地运行了一个 2.2GB 的虚拟机。
你可能会遇到的最大问题是 GC,这取决于你使用内存的方式。
来自4.1.2堆大小:
"对于32位进程模型,进程的最大虚拟地址大小通常为4 GB,尽管某些操作系统将其限制为2 GB或3 GB。堆的最大大小通常为-Xmx3800m(2 GB限制为1600m),但实际限制取决于应用程序。对于64位进程模型,最大值基本上是无限的。"
在这里找到了一个很好的答案:Windows XP上Java的最大内存。
我们最近有一些相关经验。我们最近从Solaris(x86-64版本5.10)移植到Linux(RedHat x86-64),发现在Linux上,32位JVM进程可用的内存比Solaris少。
对于Solaris来说,这几乎等同于4GB(http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit)。
过去几年里,我们使用-Xms2560m -Xmx2560m -XX:MaxPermSize=512m -XX:PermSize=512m在Solaris上运行我们的应用程序,没有任何问题。尝试将其移动到Linux上时,我们遇到了随机的内存不足错误。我们只能使用-Xms2300 -Xmx2300来保证应用程序能够始终启动。然后我们得到了支持团队的建议。
在Linux上,32位进程的最大可寻址地址空间为3GB(3072MB),而在Solaris上则是完整的4GB(4096MB)。
以下是在Solaris和Linux 64位下进行的一些测试。
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3750m MaxMemory
Error occurred during initialization of VM
Could not reserve space for ObjectStartArray
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3700m MaxMemory
Total Memory: 518520832 (494.5 MiB)
Max Memory: 3451912192 (3292.0 MiB)
Free Memory: 515815488 (491.91998291015625 MiB)
Current PID is: 28274
Waiting for user to press Enter to finish ...
$ java -version
java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) Server VM (build 20.5-b03, mixed mode)
$ which java
/usr/bin/java
$ file /usr/bin/java
/usr/bin/java: ELF 32-bit MSB executable SPARC Version 1, dynamically linked, not stripped, no debugging information available
$ prstat -p 28274
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
28274 user1 670M 32M sleep 59 0 0:00:00 0.0% java/35
顺便提一下:Java启动时似乎不会分配太多实际内存。每个实例大约只需要100 MB的内存(我启动了10个实例)
这里说的3GB可用内存并不完全准确。有一块很大的RAM被ZFS缓存使用了,但是我没有root权限去检查具体有多少。
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3650m MaxMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3600m MaxMemory
Total Memory: 516423680 (492.5 MiB)
Max Memory: 3355443200 (3200.0 MiB)
Free Memory: 513718336 (489.91998291015625 MiB)
Current PID is: 26841
Waiting for user to press Enter to finish ...
$ java -version
java version "1.6.0_41"
Java(TM) SE Runtime Environment (build 1.6.0_41-b02)
Java HotSpot(TM) Server VM (build 20.14-b01, mixed mode)
$ which java
/usr/bin/java
$ file /usr/bin/java
/usr/bin/java: ELF 32-bit LSB executable 80386 Version 1 [FPU], dynamically linked, not stripped, no debugging information available
$ prstat -p 26841
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
26841 user1 665M 22M sleep 59 0 0:00:00 0.0% java/12
$ alias java='$HOME/jre/jre1.6.0_34/bin/java'
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3500m MaxMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3450m MaxMemory
Total Memory: 514523136 (490.6875 MiB)
Max Memory: 3215654912 (3066.6875 MiB)
Free Memory: 511838768 (488.1274871826172 MiB)
Current PID is: 21879
Waiting for user to press Enter to finish ...
$ java -version
java version "1.6.0_34"
Java(TM) SE Runtime Environment (build 1.6.0_34-b04)
Java HotSpot(TM) Server VM (build 20.9-b04, mixed mode)
$ file $HOME/jre/jre1.6.0_34/bin/java
/home/user1/jre/jre1.6.0_34/bin/java: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), for GNU/Linux 2.2.5, not stripped
$ cat /proc/21879/status | grep ^Vm
VmPeak: 3882796 kB
VmSize: 3882796 kB
VmLck: 0 kB
VmHWM: 12520 kB
VmRSS: 12520 kB
VmData: 3867424 kB
VmStk: 88 kB
VmExe: 40 kB
VmLib: 14804 kB
VmPTE: 96 kB
$ alias java='$HOME/jre/jre1.7.0_21/bin/java'
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3500m MaxMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3450m MaxMemory
Total Memory: 514523136 (490.6875 MiB)
Max Memory: 3215654912 (3066.6875 MiB)
Free Memory: 511838672 (488.1273956298828 MiB)
Current PID is: 23026
Waiting for user to press Enter to finish ...
$ java -version
java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) Server VM (build 23.21-b01, mixed mode)
$ file $HOME/jre/jre1.7.0_21/bin/java
/home/user1/jre/jre1.7.0_21/bin/java: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
$ cat /proc/23026/status | grep ^Vm
VmPeak: 4040288 kB
VmSize: 4040288 kB
VmLck: 0 kB
VmHWM: 13468 kB
VmRSS: 13468 kB
VmData: 4024800 kB
VmStk: 88 kB
VmExe: 4 kB
VmLib: 10044 kB
VmPTE: 112 kB
Oracle目前拥有的JROCKIT JVM支持非连续堆使用,因此当JVM在64位Windows操作系统上运行时,32位JVM可以访问超过3.8 GB的内存(在32位操作系统上运行时为2.8 GB)。
http://blogs.oracle.com/jrockit/entry/how_to_get_almost_3_gb_heap_on_windows
JVM可以免费下载(需要注册)
http://www.oracle.com/technetwork/middleware/jrockit/downloads/index.html
对于在64位主机上运行的32位JVM,我想剩下的堆空间将是在JVM、它自己的DLL和任何32位兼容性附加组件加载之后剩余的未碎片化虚拟空间。我猜测可能有3GB的空间可用,但这取决于您在32位主机方面的表现如何。
此外,即使您可以创建一个3GB的巨大堆,您可能也不希望这样做,因为这会导致GC暂停变得潜在麻烦。一些人只是运行更多的JVM来使用额外的内存,而不是一个巨大的JVM。我想他们正在调整JVM以更好地处理巨大的堆。
很难准确知道您可以做到多好。我猜您的32位情况可以通过实验轻松确定。它肯定很难在抽象层面上预测,因为许多因素都会影响它,特别是因为32位主机上可用的虚拟空间相当受限。堆确实需要存在于连续的虚拟内存中,因此dll的地址空间的碎片化以及操作系统内核对地址空间的内部使用将决定可能的分配范围。
操作系统将使用一些地址空间来映射HW设备和它自己的动态分配。虽然此内存未映射到Java进程地址空间中,但操作系统内核无法同时访问它和您的地址空间,因此它会限制任何程序的虚拟空间大小。
加载DLL取决于实现和JVM的版本。加载操作系统内核取决于大量事项,例如版本、硬件、自上次重新启动以来已映射的内容数量等等。
我敢打赌,在32位环境下您可以获得1-2GB,在64位环境下约为3GB,因此总体改进约为2倍。