我真的很困惑。
根据java文档,Xmx是允许的最大堆大小
Xms是所需的最小Java堆大小,并在JVM启动时分配
在32位JVM(4GB内存)上,java -Xmx1536M HelloWorld无法分配足够的内存错误。
在64位JVM(4GB Ram)上,java -Xmx20G HelloWorld工作正常。但我甚至没有分配那么多虚拟或物理内存
因此,我得出结论,Java 32位在JVM启动时分配1536M,但Java 64位不是。
为什么?一个简单的Hello World不需要运行1536M。我只是指出1536M是最大值,而不是需要它
解释任何人?
答案 0 :(得分:20)
分配内存和分配地址空间之间存在区别。 Oracle JVM在启动时分配地址空间以确保堆是连续的。这允许对堆使用某些优化。
如果分配失败,那么Java将无法启动......正如您所见。它不一定使用那么多内存,而是预先分配所需的地址空间。因为你正在传递-Xmx1536m
,所以它说好了,我需要分配它,以防你需要它...并且因为它必须是连续的,所以它是预先做的,所以它可以保证它(或尝试失败)
这种行为在32位和64位JVM上都是相同的。您所看到的是32位进程的2GB每进程地址空间限制(至少,在Windows上这是限制 - 在其他平台上可能略大)导致此分配在32位上失败,其中64 -bit没有问题,因为它有更大的地址空间。但是,你说,1536米不到2GB,我应该好,对吧?不完全 - 堆不是在地址空间中分配的唯一东西,DLL和其他东西也在地址空间中分配...所以不幸的是,在32位上从2GB最大值获得连续的1536m块是不太可能的。我已经看到低于1000m的值在32位进程上失败,碎片特别糟糕,通常1200-1300m是您可以在32位上指定的最大堆。
在现代操作系统上,ASLR(地址空间布局随机化)使32位进程地址空间的碎片更加糟糕。出于安全原因,它故意将DLL加载到随机地址中...使得它更不可能在32位中获得一个大的,连续的堆。
在64位中,地址空间非常大,碎片不再是问题,可以毫无问题地分配巨型堆。即使你在32位上有4GB的RAM,但每个进程2GB的地址空间限制(至少在Windows上)通常意味着最大堆通常只有1300m左右。
答案 1 :(得分:7)
实际上,应用程序没有在启动时分配Xmx内存。
-Xms参数配置启动内存。 (What are the Xms and Xmx parameters when starting JVMs?)
64位环境允许更大的内存分配,然后32位。但实际上,它使用的是高清空间,而不是内存存储器。
有关详细信息,请参阅此其他帖子。
答案 2 :(得分:3)
在Windows下,内存分配操作与原生WinAPI低级功能(如VirtualAlloc)存在差异。
"后备"意味着在过程中分配连续区域'地址空间而不实际使这个虚拟内存区域可用。分配的区域不受实际物理RAM或交换空间的支持,并且不消耗任何可用内存。任何应用程序都可以保留任何数量的地址空间,仅受处理器的内存寻址能力(位数)的限制。
"犯下"意味着支持以前的一些"保留"具有实际内存的内存 - RAM或交换空间,使其实际可读/可写。此内存取自可用的OS虚拟内存池(RAM和交换)。
"提交"的替代方案内存(从池中取一个空白页)是"映射"一个文件进入以前的"保留"记忆。这不会占用交换池中的内存,而是以类似于进程特定区域的专用交换空间的方式使用映射文件。地址空间。
本机Windows应用程序(如JVM本身)为将来需要的所有堆保留内存,但仅在需要时提交。 高级内存操作,如malloc()样式函数或" new"运营商真的做了#34;承诺"根据需要甚至做他们自己的堆管理逻辑用户模式,其中内存由大块提交,因为它是CPU密集型内核调用,并且以页面(4k)粒度工作。
在流程启动期间JVM"预留" -Xmx内存,但"提交"只有-Xms的数量。剩余的保留内存随着堆的增长而按需提交。因此,堆可以增长到可用内存或-Xmx参数,以较小者为准。