JVM 的内存结构中主要有 “堆”、“虚拟机栈”、“方法区”,所以 JVM 规范要求提供了这三个区域的参数设置。

堆内存设置

整个堆内存大小设置

参数名称 含义 默认值
-Xms 初始堆大小 物理内存的1/64(<1GB) 默认空余堆内存小于40%(MinHeapFreeRatio)时,JVM就会增大堆直到-Xmx的最大限制
-Xmx 最大堆大小 物理内存的1/4(<1GB) 默认空余堆内存大于70%(MaxHeapFreeRatio)时,JVM会减少堆直到 -Xms的最小限制
-XX:MaxHeapFreeRatio 空闲堆大于该比例时堆缩小
-XX:MinHeapFreeRatio 空闲堆小于该比例时堆增大

JVM 启动的时候初始堆大小通常为 -Xms 指定大小,随着程序的一直执行(产生新对象)那么堆的大小会一直增长直到达到 -Xmx
假设经历过一次 GC 后,堆中的空闲空间大于 -XX:MaxHeapFreeRatio 时,实际堆大小就会被回收,不低于 -Xms 指定大小;如果后续程序继续执行,堆中的剩余空间小于 -XX:MinHeapFreeRatio 时,实际堆大小就会继续增长,不超过 -Xmx 指定大小。

-Xms 等同于 -XX:InitialHeapSize; -Xmx 等同于 -XX:MaxHeapSize

新生代堆内存大小设置

新生代中会包含两个部分,分别是 Eden 区和两个 Survivor 区:

参数名称 含义 默认值 备注
-XX:NewSize 设置年轻代最小大小
-XX:MaxNewSize 设置年轻待最大大小
-XX:SurvivorRatio Eden区与Survivor区的大小比值 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:NewRatio 年轻代(Eden+2*Survivor)与老年代的比值 -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5

老年代堆内存大小设置

老年代堆大小的设置需要通过 -XX:NewRatio 来按比例划分。
比如你设置了 4GB内存 ,给定的 -XX:NewRatio=3 ,那么 年轻代 : 老年代 = 1 : 3 ,所以老年代会占用3个G,新生代占用1个G。

非堆内存设置

永久代 (JDK7及以前)

凡是看过我《JVM运行时内存结构》的胖友们 (/偷偷看) ,都知道方法区是虚拟机规范给定的一个概念,里面会存放类信息常量池静态变量等内容。 Hotspot 则将方法区的内容都丢入了永久代中(方法区是概念,永久代是实现)。

参数名称 含义 默认值
-XX:PermSize 永久代的初始值 物理内存的1/64(<1GB)
-XX:MaxPermSize 永久代的最大值 物理内存的1/4(<1GB)

元空间 (JDK8及以后)

永久代在JDK8以前存在于虚拟机管理的内存中;而元空间就是物理上也独立于堆,存在于直接内存中。

参数名称 含义 默认值
-XX:MetaspaceSize 元空间的初始值 64位JVM,20.75MB
XX:MaxMetaspaceSize 元空间的最大值 默认为0,表示无上限

由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量Full GC,通常都是由于永久代或元空间发生了大小调整,基于这种情况,一般建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样的值,并设置得比初始值要大,对于8G物理内存的机器来说,一般我会将这两个值都设置为256M(PS:读者可以根据自己的实际情况再调整)。

虚拟机栈设置

这一块就不用多说了吧~

参数名称 含义 默认值
-Xss 每个线程的堆栈大小 JDK5.0以后每个线程堆栈大小为1M。在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右
一般小的应用,如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。

-XX:ThreadStackSize 属于不稳定选项,可能随时发生变更

参考资料