分配内存和分配地址空间之间是有区别的。Oracle JVM 在启动时分配地址空间,以确保堆是连续的。这允许对堆使用某些优化。
如果分配失败,则 Java 将不会启动...正如你所看到的。它不一定使用那么多内存,但它正在预先分配所需的地址空间。既然你通过了,它说好,我需要分配,以防你需要它...并且由于它必须是连续的,因此它会预先执行此操作,因此可以保证它(或尝试失败)。-Xmx1536m
此行为在 32 位和 64 位 JVM 上是相同的。您看到的是32位进程的每个进程2GB的地址空间限制(至少在Windows上这是限制 - 在其他平台上可能略大),导致此分配在32位上失败,其中64位没有问题,因为它具有更大的地址空间。但是,你说,1536m不到2GB,我应该很好,对吧?不完全是 - 堆不是地址空间中分配的唯一东西,DLL和其他东西也分配在地址空间中...因此,不幸的是,在32位上从2GB最大值中获得连续的1536m块是非常不可能的。我见过低于1000m的值在32位进程上失败,碎片特别严重,通常1200-1300m是您可以在32位上指定的最大堆。
在现代操作系统上,ASLR(地址空间布局随机化)使 32 位进程地址空间的碎片化更加严重。出于安全原因,它有意将 DLL 加载到随机地址中...使您更不可能在 32 位中获得一个大的、连续的堆。
在 64 位中,地址空间非常大,以至于碎片不再是问题,并且可以毫无问题地分配巨大的堆。但是,即使您在32位上有4GB的RAM,每个进程2GB的地址空间限制(至少在Windows上)通常意味着最大堆通常只有1300m左右。