设置JVM堆空间大小
原理
JVM在执行Java程序时会把它所管理的内存划分为若干个不同的运行时数据区域,主要包括:程序计数器、方法区、虚拟机栈、本地方法栈和堆:
- 程序计数器可以看作时当前线程所执行的字节码的行号指示器。
- 方法区用于存储被JVM加载的类信息、常量、静态变量等数据。
- 虚拟机栈存储的时Java方法执行的线程内存模型,每一个方法被调用到执行完毕的过程,就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。
- 本地方法栈和虚拟机栈的功能相同,差别是本地方法栈只为本地方法调用服务。
- 堆是JVM管理内存中占用比例最大的一块,用于存储Java程序对象实例,几乎所有的对象实例内存都在这里分配。从内存回收角度和经典垃圾收集器分带理论上看,堆内存空间一般被分为:新生代、老年代、永久代、Eden空间、From/To Survivor等区域。各代功能和划分说明可以参考:https://www.cnblogs.com/fangfuhai/p/7206944.html 。
针对堆空间的优化是Java性能调优的重点之一。如果没有设置JVM堆空间大小,JVM会根据服务器物理内存大小设置默认堆大小的值。例如,在64位的服务器端,当物理内存小于192MB时,JVM堆大小默认选为物理内存的一半;当物理内存大192MB且小于128GB时,JVM堆大小默认选为物理内存的四分之一;当物理内存大于等于128GB时,都为32GB。通常情况下,Java应用程序的会通过参数指定堆大小,具体方法下文会有说明。
应用程序选用多大的堆空间大小及配比,一般要根据程序的GC情况和服务器内存资源进行综合评估,是个循序渐进不断优化的过程,如果垃圾回收(GC)频繁触发,可以尝试增加堆空间缓解。
推荐配置原则:
- 应用程序运行时,计算老年代存活对象的占用空间大小X。程序整个堆大小(Xmx和Xms)设置为X的3~4倍;永久代PermSize和MaxPermSize设置为X的1.2~1.5倍。年轻代Xmn的设置为X的1~1.5倍。老年代内存大小设置为X的2~3倍。
- JDK官方建议年轻代占整个堆大小空间的3/8左右。
- 完成一次Full GC后,应该释放出70%的堆空间(30%的空间仍然占用)。
修改方式
在Java应用程序启动时,添加如下参数并设置大小:
参数 |
说明 |
---|---|
-Xmx |
设置JVM最大可用堆内存大小。 |
-Xms |
设置初始堆大小,一般和Xmx保持一致。 |
-Xmn |
设置年轻代堆大小。 |
-Xss |
设置每个线程的堆大小。JDK 1.5以后每个线程堆栈大小默认为1MB,1.5以前为256K。 |
-XX:NewRatio= |
设置年轻代(包括Eden和两个Survivor区)与老年代的比值(不包括永久代)。如设置为4,则年轻代与老年代所占比值为1:4,年轻代占整个堆栈的1/5。 |
-XX:SurvivorRatio= |
设置年轻代中Eden区与Survivor区的大小比值。如设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6。 |
-XX:MaxPermSize= |
设置永久代堆大小。 |
举例:
java -Xmx3600m -Xms3600m -Xmn2g -Xss128k
设置最大堆空间为3600MB,初始化堆大小为3600MB,年轻代大小为2GB,线程堆大小为128KB。