基于JDK8的内存结构的调优
要想进行内存调优,就要先要对其内存结构有清楚的认识
JDK8的内存结构
JDK8的内存结构主要包括:程序计数器、虚拟机栈、本地方法栈、堆、元空间
其中堆又划分为:老年代、年轻代、其中年轻代又划分为Eden区和Survivor区
对于JDK8的内存调优主要针对的是堆和元空间。其中常用的JVM参数如下
-server
JVM的server模式,在多CPU服务器中性能可以得到很好的发挥。由于JDK的64位版本只支持server模式,因此在这种情况下选项是隐式的
-Xmx
指定堆所分配内存的最大值,等同于-XX:MaxHeapSize。单位默认为byte,必须是1024的倍数。例如
-Xmx1G
-Xmx1024M
-Xmx1048576K
-Xmx1073741824
-Xms
指定堆所分配内存的初始值,默认单位为byte。如果不设置这个初始值,那么初始值将默认为老年代和年轻代分配内存的大小的总和。
对于生产环境的部署,-Xms和-Xmx通常设为相同的值
-Xmn
指定堆的年轻代分配内存的初始值和最大值,默认单位为byte
堆的年轻呆区域用于存放新生对象,与其他区域相比,在这个区域执行垃圾回收的频率更大。如果年轻代的内存太小,那么将执行多次垃圾会输,如果太大,那么执行一次完整的垃圾回收需要的时间太长
一般建议把年轻代的大小保持在整个堆大小的50%-25%
除了使用-Xmn选项设置年轻代的初始值和最大值,还能使用-XX:NEwSize来设置年轻代的初始值,-XX:MaxnewSize设置年轻代的最大值
-XX:NewRatio
指定老年代和年轻代空间大小的比率,默认为2。
另外,年轻代分配内存设置的优先级如下
- 高优先级:-XX:NewSize -XX:MaxNewSize
- 中优先级: -Xmn
- 低优先级: -XX:NewRatio
-XX:SurvivorRatio
指定Eden去和一个Survivor区的空间大小的比率。默认为8
-XX:MetaspaceSize
指定元空间第一次触发垃圾回收的内存大小的阈值。当元空间内存占用不断增大,直到达到这个阈值时,就会触发一次垃圾回收。所以适当增大这个阈值,会减少垃圾回收的次数,默认值根据平台而定,一般情况下大约20.8MB
-XX:MaxMetaspaceSize
指定元空间所分配内存的最大值,默认是没有限制的,取决于系统的可用内存量,理论上可以占满整个系统的内存。
所以需要适当设置它的大小
内存调优实操
尽可能把堆内存空间设置大一些,减少内存回收的次数。当服务器上的可用内存还有12GB的时候,可以先指定堆所分配内存的最大值和初始值都为8GB。一般情况下,年轻代内存大小需在整个堆大小的50%-25%,那就指定年轻代内存大小为3GB。再把Eden区和一个Survivor区的空间大小比例设为4。元空间第一次触发垃圾回收的内存大小的阈值设为256MB,一般情况下足够使用。元空间所分配内存的最大值设置为512MB,为了避免极端情况下占用大量内存。另外还需要明确指定JVM以server模式启动。
内存调优的参数基本确定后,用它启动一个名为one-more-study-0.0.1-SNAPSHOT.jar的jar文件:
java -server -Xmx8G -Xms8G -Xmn3G -XX:SurvivorRatio=4 -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -jar one-more-study-0.0.1-SNAPSHOT.jar
然后使用jmap -heap命令查看对应Java进程的内存配置和使用情况。