-Xms和-Xmx标志会保留计算机的资源吗?

23
我知道JVM进程的-Xms标志是允许JVM进程使用特定数量的内存来初始化其进程。在考虑Java应用程序性能时,通常建议在启动应用程序时将-Xms-Xmx设置为相同的值,例如-Xms2048M -Xmx2048M
我很好奇-Xms-Xmx标志是否意味着JVM进程做了一个保留,以防其他进程在同一台机器上使用它。
这是正确的吗?

@PeterLawrey 感谢您的编辑。 - ParkCheolu
3个回答

14

Xmx 仅仅是保留了虚拟地址空间。而Xms 实际上分配(提交)了内存,但不一定会预读。

不同的操作系统对于内存分配的响应有所不同。

Windows 允许你保留非常大的地址空间(Xmx),但不允许过度提交(Xms)。限制由交换文件和物理内存共同决定。例外情况是大页面(需要通过组策略设置启用),这将限制它的物理内存。

Linux 的行为更加复杂,取决于 vm.overcommit_memory 及相关 sysctl 和传递给mmap 系统调用的各种标志,这在某种程度上可以通过 JVM 配置标志来控制。行为范围可以从 a) Xms 超出总内存+交换空间到 b) Xmx 受可用物理内存的限制。


4
有趣的是,当使用-XX:+AlwaysPreTouch时,不应该预先填充内存吗? - Eugene
2
@Eugene 确实是这样,因此才会说“不一定”。 - the8472
@Eugene 太棒了!我一直在寻找 AlwaysPreTouch,却不知道它的存在。这就解释了为什么我的 Java 进程只使用了 10 GB 的内存,即使使用 -Xms 参数启动时设置了 200 GB。 - asgs

9
简短回答:这取决于操作系统,但在所有流行的操作系统中都肯定是不行的。
我将以Linux的内存分配术语为例。-Xms和-Xmx指定JVM堆的最小和最大大小。这些大小反映了可以物理映射到RAM页面的虚拟内存分配,称为进程的常驻大小。当JVM启动时,它会分配-Xms数量的虚拟内存。一旦您在堆上动态创建更多对象,这些虚拟内存可以映射到常驻内存(物理内存)。此操作不需要JVM从操作系统请求任何新分配,但会增加您的RAM利用率,因为这些虚拟页面现在实际上也有相应的物理内存分配。但是,一旦您的进程在消耗完其RAM上的Xms分配后尝试在堆上创建更多对象,它就必须向操作系统请求更多的虚拟内存,这可能/可能不会在以后根据需要映射到物理内存。这个限制是您的-Xmx分配。
请注意,这一切都是因为Linux中的内存是共享的。因此,即使进程事先分配了内存,它得到的也只是虚拟内存,这只是一个可寻址的连续虚构分配,可能会或可能不会根据需求映射到真实的物理页面。阅读this answer以了解流行操作系统中内存管理工作的简要描述。这里有更详细(略有过时但非常有用)关于Linux内存管理如何工作的信息。
另外请注意,这些标志仅影响堆大小。您将看到的常驻内存大小将大于当前的JVM堆大小。更具体地说,JVM消耗的内存等于其堆大小加上DIRECT MEMORY,这反映了来自方法堆栈、本地缓冲区分配等方面的内容。

6
JVM进程是否会为特定的内存量进行预留?
是的,JVM在启动时会保留由Xms指定的内存,并可能保留最多Xmx的内存,但保留不一定在物理内存中,也可以在交换空间中。JVM页面将根据需要在内存中进行交换。
为什么建议Xms和Xmx具有相同的值?
注意:通常建议在专用于单个应用程序的机器上(或者没有许多应用程序竞争系统资源的情况下)设置Xms和Xmx。这并不适用于所有情况。
避免堆大小:
JVM最初使用由Xms值指定的堆大小启动。当应用程序分配对象导致堆耗尽时,JVM开始增加堆大小。每次JVM增加堆大小时,它必须向操作系统请求额外的内存。这是一个耗时的操作,会导致增加gc暂停时间,从而影响请求的响应时间。
应用程序长期行为:
尽管我不能概括,但许多应用程序长期运行最终会增长到最大堆值。这是另一个原因要从最大内存开始,而不是随着时间的推移增加堆并创建不必要的堆重置开销。这就像要求应用程序在最开始就占用内存,而它最终会占用内存一样。
GC的数量:
从小堆大小开始会导致更频繁的垃圾回收。更大的堆大小减少了发生gc的次数,因为分配给对象的内存更多。但是必须注意,增加的堆大小会增加gc暂停时间。只有在垃圾回收已经调整好并且暂停时间不随着堆大小的增加而显著增加时才具有优势。
再说一个原因是服务器通常配备大量内存,那么为什么不使用可用资源呢?

1
-Xms 是内存大小,区域配置适应该大小。如果有大量未使用的 tenured 空间,则实际故障大小可以小得多。 - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接