64位操作系统上32位 JVM 的最大 Java 堆大小

问题不在于32位操作系统的最大堆大小,因为32位操作系统的最大可寻址内存大小为4GB,而 JVM 的最大堆大小取决于可以保留多少连续空闲内存。

I'm more interested in knowing the maximum (both theoretical and practically achievable) heap size for a 32-bit JVM running in a 64-bit OS. Basically, I'm looking at answers similar to 关于 SO 的相关问题中的数字.

至于为什么使用32位 JVM 而不是64位 JVM,原因不在于技术,而在于管理/官僚——在生产环境中安装64位 JVM 可能为时已晚。

316889 次浏览

在64位操作系统上,32位 JVM 的限制与在32位操作系统上的32位 JVM 的限制完全相同。毕竟,32位 JVM 将在32位虚拟机中运行(在虚拟化意义上) ,所以它不会知道它在64位 OS/机器上运行。

在64位操作系统上运行32位 JVM 相对于32位操作系统的一个优势是,您可以拥有更多的物理内存,因此不会频繁地遇到交换/分页。但是,只有在拥有多个进程时,才能真正充分实现这一优势。

您没有指定 哪个操作系统。

Under Windows (for my application - a long running risk management application) we observed that we could go no further than 1280MB on Windows 32bit. I doubt that running a 32bit JVM under 64bit would make any difference.

We ported the app to Linux and we are running a 32bit JVM on 64bit hardware and have had a 2.2GB VM running pretty easily.

您可能遇到的最大问题是 GC,这取决于您使用内存的目的。

32位 JVM 希望拥有一个单独的大块内存并使用原始指针,因此不能使用超过4Gb 的内存(因为这是32位的限制,也适用于指针)。这包括 Sun 和——我非常肯定——还包括 IBM 的实现。我不知道例如 JRockit 或者其他的32位实现是否有一个大的内存选项。

如果您希望达到这个限制,那么应该强烈考虑开始一个并行跟踪,为您的生产环境验证一个64位 JVM,以便在32位环境崩溃时做好准备。否则你将不得不在压力下工作,这从来都不是好事。


编辑2014-05-15: 甲骨文常见问题:

32位 JVM 的最大理论堆限制是4G。由于各种额外的限制,例如可用交换、内核地址空间使用、内存碎片和 VM 开销,实际上这个限制可以低得多。在大多数现代32位 Windows 系统中,堆的最大大小从1.4 G 到1.6 G 不等。在32位 Solaris 内核中,地址空间限制在2G。在运行32位 VM 的64位操作系统上,最大堆大小可能更高,在许多 Solaris 系统上接近4G。

(http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit)

应该会好很多

对于一个运行在64位主机上的32位 JVM,我想堆剩下的就是在 JVM 之后可以使用的任何完整的虚拟空间、它自己的 DLL 以及任何已经加载的 OS 32位兼容性。作为一个大胆的猜测,我认为3GB 应该是可能的,但是这取决于您在32位主机环境中的表现如何。

此外,即使您可以创建一个巨大的3GB 堆,您也可能不希望这样做,因为这将导致 GC 暂停变得潜在的麻烦。有些人只是运行更多的 JVM 来使用额外的内存,而不是一个巨大的内存。我想他们现在正在对 JVM 进行调优,以便更好地处理巨大的堆。

很难知道你能做到什么程度。我想你的32位情况可以很容易地通过实验来决定。当然,抽象地预测是很困难的,因为其中包含了很多因素,特别是因为32位主机上可用的虚拟空间受到了相当大的限制。.堆确实需要存在于连续的虚拟内存中,因此 dll 的地址空间碎片和 OS 内核对地址空间的内部使用将决定可能的分配范围。

操作系统将使用一些地址空间来映射 HW 设备和它自己的动态分配。虽然这个内存没有映射到 java 进程地址空间,但是操作系统内核不能同时访问它和您的地址空间,因此它会限制任何程序的虚拟空间的大小。

加载 DLL 取决于 JVM 的实现和发布。加载操作系统内核取决于大量的事情,发布,硬件,有多少事情它已经映射到目前为止,因为上次重启,谁知道..。

总结一下

我打赌您在32位的地方获得1-2GB,在64位中获得大约3 GB,因此大约 2x的整体改进。

我试过在32位 Linux 机器上将堆大小设置为2200M,JVM 工作得很好。当我设置为2300M 时,JVM 没有启动。

来自 4.1.2 Heap Sizing:

”对于32位进程模型,控件的最大虚拟地址大小 进程通常为4GB,尽管有些操作系统将其限制为 最大堆大小通常为 -Xmx3800m (1600m) 2GB 限制) ,但实际的限制取决于应用程序。 对于64位进程模型,最大值基本上是无限的。”

在这里找到了一个不错的答案: 在 WindowsXP 上 Java 最大内存

在 Solaris 上,自从 Solaris 2.5以来(大约10年前) ,这个限制一直是3.5 GB

We recently had some experience with this. We have ported from Solaris (x86-64 Version 5.10) to Linux (RedHat x86-64) recently and have realized that we have less memory available for a 32 bit JVM process on Linux than Solaris.

对于 Solaris 来说,这个 http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit 大约是4 GB。

在过去的几年里,我们使用 -Xms2560m -Xmx2560m -XX:MaxPermSize=512m -XX:PermSize=512m运行我们的应用程序,在 Solaris 上没有出现任何问题。我们试图把它移动到 linux,但是在启动时出现了内存不足的随机错误。我们只能让它始终在 - Xms2300-Xmx2300上启动。然后我们得到了支援的通知。

Linux 上的32位进程有一个 最大可寻址地址空间 3gb (3072mb) ,而在 Solaris 上是 完整的4gb (4096mb)。

你可以问 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)");
}
}

这将基于默认堆分配报告“ Max Memory”。所以你仍然需要使用 -Xmx(在 HotSpot上)。我发现运行在 Windows 7 Enterprise 64位上,我的 32位 HotSpot JVM 可以分配最多1577MiB:

[C:scratch]> java -Xmx1600M MaxMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
[C:scratch]> java -Xmx1590M MaxMemory
Total Memory: 2031616 (1.9375 MiB)
Max Memory:   1654456320 (1577.8125 MiB)
Free Memory:  1840872 (1.75559234619 MiB)
[C:scratch]>

而在同一个操作系统上使用 64位 JVM 时,它当然要高得多(大约3TiB)

[C:scratch]> java -Xmx3560G MaxMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
[C:scratch]> java -Xmx3550G MaxMemory
Total Memory: 94240768 (89.875 MiB)
Max Memory:   3388252028928 (3184151.84297 MiB)
Free Memory:  93747752 (89.4048233032 MiB)
[C:scratch]>

正如其他人已经提到的,这取决于操作系统。

对于64位主机操作系统,如果 JVM 是32位的,那么它仍然取决于主机操作系统,很可能像上面演示的那样。

更新20110905 : 我只是想指出一些其他的观察/细节:

  • 我运行它的硬件是64位的,安装了6GB 的实际 RAM。操作系统是 Windows7企业版,64位
  • 可以分配的 Runtime.MaxMemory的实际数量也取决于操作系统的 工作装置。我曾经在运行 VirtualBox 的时候运行过这个程序,发现我可以用 -Xmx1590M成功地启动 HotSpot JVM,而且必须做得更小。这也意味着,根据当时的工作集大小,你可能会得到超过1590M (尽管由于 Windows 的设计,我仍然坚持32位的工作集大小将低于2GiB)

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

我在使用 Android应用开发者块编辑器的 JVM 时遇到了同样的问题。它把堆放在最大925米。这是不够的,但我不能设置超过1200米左右,这取决于我的机器上的各种随机因素。

我从 Firefox 下载了64位的 Beta 浏览器 Night,以及 JAVA 764位的版本。

我还没有找到新的堆限制,但是我刚刚打开了一个堆大小为 5900米的 JVM。没问题!

我运行 Win764位终极在一台机器上与24gb 内存。

至于为什么使用32位 JVM 而不是64位 JVM,原因不在于技术,而在于管理/官僚..。

当我在 BEA 工作时,我们发现平均应用程序实际上是在64位 JVM 中运行的 跑得更慢,然后它在32位 JVM 中运行。在某些情况下,性能下降幅度高达25% 。因此,除非您的应用程序确实需要所有这些额外的内存,否则最好设置更多的32位服务器。

据我回忆,BEA 专业服务人员遇到的使用64位最常见的三个技术理由是:

  1. 这个应用程序正在处理多个大规模图像,
  2. 这个应用程序正在进行大量的数字处理,
  3. The application had a memory leak, the customer was the prime on a 政府合同,他们不想花时间和 追踪内存泄漏的代价。(使用大容量内存 堆会增加 MTBF,质数仍然会得到支付)

.

下面是在 Solaris 和 Linux 64位下进行的一些测试

Solaris 10-SPARC-T5220计算机,32GB 内存(大约9GB 空闲)

$ 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

BTW: Apparently Java does not allocate much actual memory with the startup. It seemed to take only about 100 MB per instance started (I started 10)

Solaris 10-x86-VMWare VM,8GB 内存(大约3GB 空闲 *)

3GB 的空闲内存并不是真的。ZFS 缓存使用了大量的 RAM,但是我没有 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

RedHat 5.5-x86-VMWare VM,4 GB RAM (大约使用了3.8 GB ——缓冲区中使用了200 MB,缓存中使用了3.1 GB,因此大约有3 GB 的空闲空间)

$ 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

使用 JRE 7的同一台机器

$ 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

这里还有一点是关于热点32位 JVM 的:- 本机堆容量 = 4Gig-Java 堆-PermGen;

对于32位的 JVM 来说,由于 JavaHeap 和本机 Heap 正在进行竞争,因此它可能变得特别棘手 你的 Java 堆越大,本地堆就越小。尝试为32位虚拟机设置一个大的堆 例如,2.5 GB + 会增加原生 OutOfMemory 错误的风险,这取决于您的应用程序占用的空间, 线程数等。

Theoretical 4gb, but in practice (for IBM JVM):

Win 2k864,IBM WebSphere Application Server 8.5.532位

C: IBM WebSphere AppServer bin > management esdk.Bat-listable-verose CWSDK1003I: SDK: CWSDK1005I: SDK: 1.6 _ 32-com.Ibm.网球。Sdk.版本。1.6 _ 32 = 1.6-com.Ibm.网球。Sdk.比特。1.6 _ 32 = 32-com.Ibm.网球。Sdk.位置。1.6 _ 32 = ${ WAS _ INSTALL _ ROOT }/java-com.Ibm.网球。Sdk.平台。1.6 _ 32 = windows-com.Ibm.网球。Sdk.建筑。1.6 _ 32 = x86 _ 32-com.Ibm.网球。Sdk.NativeLibPath.1.6 _ 32 = ${ WAS _ INSTALL _ ROOT }/lib/national/win/x86 _ 32/ CWSDK1001I:. C: IBM WebSphere AppServer java bin > java-Xmx2036 MaxMemory JVMJ9GC017E-Xmx,1M JVMJ9VM015W j9gc26(2) : 无法创建 Java 虚拟机。 C:\IBM\WebSphere\AppServer\java\bin>java -Xmx2047M MaxMemory 总内存: 4194304(4.0 MiB) Max Memory: 2146435072(2047.0 MiB) 免费内存: 3064536(2.9225692749023438 MiB) C:\IBM\WebSphere\AppServer\java\bin>java -Xmx2048M MaxMemory JVMJ9VM015W j9gc26(2) : ; 2G Could not create the Java virtual machine.

RHEL 6.464,IBM WebSphere Application Server 8.5.532位

[ bin ] ./java-Xmx3791M MaxMemory 总内存: 4194304(4.0 MiB) Max Memory: 3975151616(3791.0 MiB) 免费内存: 3232992(3.083221435546875 MiB) [ root@nagios1p bin ] # ./java-Xmx3793M MaxMemory Total Memory: 4194304 (4.0 MiB) Max Memory: 3977248768(3793.0 MiB) 免费内存: 3232992(3.083221435546875 MiB) [ bin ] #/opt/IBM/WebSphere/AppServer/bin/managesdk.sh-listCompleable-verose CWSDK1003I: Available SDKs : CWSDK1005I: SDK name: 1.6 _ 32 - com.ibm.websphere.sdk.version.1.6_32=1.6 -com.ibm.webSphere e.sdk.bits.1.6 _ 32 = 32 - com.ibm.webSphere e.sdk.location.1.6 _ 32 = ${ WAS _ INSTALL _ ROOT }/java - com.ibm.webSphere e.sdk.platform.1.6 _ 32 = linux - com.ibm.webSphere e.sdk.Architecture. 1.6 _ 32 = x86 _ 32 NativeLibPath. 1.6 _ 32 = ${ WAS _ INSTALL _ ROOT }/lib/national/linux/x86 _ 32/ CWSDK1001I: 成功执行了请求的 Managesdk 任务。

The limitation also comes from the fact that for a 32 bit VM, the heap itself has to start at address zero if you want all those 4GB.

考虑一下,如果你想通过以下途径引用一些东西:

0000....0001

例如: 一个具有这个特定位表示的引用,这意味着您正试图从堆中访问第一个内存。为了实现这一点,堆必须从地址零开始。但这从来没有发生过,它从零开始:

    | ....               .... {heap_start .... heap_end} ... |
--> (this can't be referenced) <--

因为在 OS中堆从不从地址零开始,所以有相当多的位从未从 32位引用中使用,因此可以引用的堆比较低。