之前写的一篇设计的jvm调优并没有给出为什么这样调整的理由,最近一直再搞这个,说下我自己的理解
先了解下概念,jvm中几个重要的参数
-Xmn 设置新生代的初始值和最大值,单位默认是字节,可以使用k,m,g
-Xms 设置初始 Java 堆大小,单位默认是字节,可以使用k,m,g
-Xmx 设置最大 Java 堆大小,单位默认是字节,可以使用k,m,g
-Xss 设置 Java 线程堆栈大小,单位默认是字节,可以使用k,m,g
一般情况下,jvm设置的Xms,以及Xmx参数是根据程序所能使用的内存空间来确定的,同时根据你的实际情况来设定,一般是按照可用内存的一半进行设定,如果对除堆数据外的,其他数据增量不明显,同时其他程序所占用的内存空间较小,可以适当加大比例。
Xmn 是年轻代大小
Xmx=Young+Old+Permnant
image.png
Xmn=Eden+Survivor*2
Eden和Survivor比值通常也需要设定,-XX:SurvivorRatio=8 默认值为8,就是Eden/Survivor=8,每块Survivor占Young的1/10
-XX:PermSize=300m
-XX:MaxPermSize=300m
Per永久代设定,该值同样考虑真实的程序运行情况,若过小可能因为FGC导致程序停顿时间增加
-XX:ParallelGCThreads=4 程序并发线程数,根据实际运行环境的核数决定,默认值为8,
一般我们使用的服务器按照线程数来作为核数值(有的服务器的核数低于线程数。例如E5-2620的服务器,核数为24,线程数为48)核数不足8的,可以按照实际核数设定
-XX:MaxTenuringThreshold=3:一般一个对象在Young经过多少次GC后会被移动到OLD区。在年轻代中进行的事Minor GC
-XX:+UseConcMarkSweepGC 并发标记清除(CMS)收集器
-XX:+CMSParallelRemarkEnabled 启用并行标记,降低标记停顿
-XX:+UseParNewGC 对年轻代采用多线程并行回收,这样收得快
-XX:+UseCMSCompactAtFullCollection 在FULL GC的时候对年老代的压缩,Full GC后会进行内存碎片整理,过程无法并发,空间碎片问题没有了,但提顿时间不得不变长了
-XX:CMSFullGCsBeforeCompaction=3 多少次Full GC 后压缩old generation一次
设置为0,就是每次GC都会压缩老年代
-XX:LargePageSizeInBytes=128m 内存页的大小
-XX:+UseFastAccessorMethods 原始类型的快速优化,建议开启
-XX:+UseCMSInitiatingOccupancyOnly 使用设定的回收阈值(下面指定的70%)开始CMS收集,如果不指定,JVM仅在第一次使用设定值,后续则自动调整
-XX:CMSInitiatingOccupancyFraction=70 使用cms作为垃圾回收使用70%后开始CMS收集
以上两个参数是联合使用的
此值是根据公式:
(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100>=Xmn
按照此公式设定不会出现promotion failed错误
理论上我们会减少Full gc的次数,同时尽量使用Minor GC,因为Full GC会导致服务暂时不可用.
同时可以手动进行Full GC
jmap -histo:live PID
附上jvm优化后配置:
JAVA_OPTS="-server \
-Xms4g \
-Xmx4g \
-Xmn700m \
-Xss256K \
-XX:MaxDirectMemorySize=4096m \
-XX:PermSize=300m \
-XX:MaxPermSize=300m \
-XX:+UseParNewGC \
-XX:SurvivorRatio=2 \
-XX:ParallelGCThreads=4 \
-XX:+UnlockDiagnosticVMOptions \
-XX:ParGCCardsPerStrideChunk=32768 \
-XX:+UseConcMarkSweepGC \
-XX:-CMSParallelRemarkEnabled \
-XX:+UseCMSCompactAtFullCollection \
-XX:CMSFullGCsBeforeCompaction=0 \
-XX:+ParallelRefProcEnabled \
-XX:+CMSClassUnloadingEnabled \
-XX:CMSInitiatingOccupancyFraction=78 \
-XX:+UseCMSInitiatingOccupancyOnly \
-XX:+ExplicitGCInvokesConcurrent \
-Dsun.rmi.dgc.client.gcInterval=14400000 \
-Dsun.rmi.dgc.server.gcInterval=14400000 \
-XX:+AlwaysPreTouch \
-XX:+PrintGCDetails \
-XX:+PrintGCTimeStamps \
-XX:+PrintGCDateStamps \
-XX:+PrintTenuringDistribution \
-XX:+PrintGCApplicationStoppedTime \
-XX:-OmitStackTraceInFastThrow \
-Xloggc:/letv/logs/tomcat/gc.log \
-Dtomcat.log=/letv/logs/tomcat \
-Djava.net.preferIPv4Stack=true"
另外推荐一个分析gc.log的网站,大家可以免费使用下
](https://gceasy.io/
网友评论