JVM与tomcat参数与优化
1,JVM参数
官网:『https://docs.oracle.com/javase/10/jrockit-hotspot/command-line-options.htm#JRHMG127』
image.png
1)HotSpot虚拟机有很多非稳定参数Unstable Options
,以-XX
开头的参数。
-XX:+<option>
开启option参数。
-XX:-<option>
关闭option参数。
-XX:<option>=<value>
将option参数设置成value值。
2)垃圾收集优化常用参数
-XX:+DisableExplicitGC
禁止在运行期间,显示调用System.gc()
,GC触发的时机由Garbage Collector
全权掌握。
-XX:UseConcMarkSweepGC
:设置JVM堆的老年代
使用CMS并发收集器。
-verbose:gc
:输出虚拟机中GC的详细信息。
[Full GC 168K->97K(1984K), 0.0253873 secs]
有168K-97K=71K的对象容量被回收,1984K为堆内存的总容量,耗时0.0253873秒。
-XX:+PrintGC
,开启GC日志打印。显示结果例如:
[Full GC 131115K->7482K(1015808K), 0.1633180 secs]
-XX:+PrintGCDetails
,打印GC回收的详细信息。如full gc整理Tenured和Perm区。[Full GC (System) [Tenured: 0K->2394K(466048K), 0.0624140 secs] 30822K->2394K(518464K), [Perm : 10443K->10443K(16384K)], 0.0625410 secs] [Times: user=0.05 sys=0.01, real=0.06 secs]
-XX:+PrintGCDateStamps
:GC时间,记录的是系统时间,比-XX:-PrintGCTimeStamps易读。
-Xloggc:
输出GC 详细日志信息至指定文件。
3)JVM -XX 性能常用参数
-XX:NewSize
:设置新生代内存初始大小
-XX:MaxNewSize
:设置最大新生代内存大小
-XX:OldSize
:年老代初始大小。堆中默认年轻代:年老代 = 1:2,一般年老代容量达到80%时,就会发生full gc。
-XX:PermSize
:设置持久代初始大小。JDK8改为-XX:MetaspaceSize
-XX:MaxPermSize
:设置持久带最大内存大小。JDK8改为-XX:MaxMetaspaceSize
。
-XX:NewRatio
:设置新生代与老年代的比例。默认值为2,即年老代:年轻代 = 2:1
-XX:SurvivorRatio
:设置新生代中Eden区和两个survivor区的比例。默认为8,即s1:s2:eden = 1:1:8
4)JVM常用性能参数
-server
:启动略慢性能高,新生代采用parallel gc,老年代单线程标记-整理算法gc。-client 采用 Serial gc串行,启动快,性能低。
-Xmn
:设置新生代内存大小,设置较大会减少年老代大小。等效于NewSize=MaxNewSize
-Xms
:JVM初始堆大小。
-Xmx
:JVM最大堆大小。一般设置-Xms=-Xmx=(eg:2048m),避免JVM反复申请内存,导致性能大起大落。
-Xss
:设置JVM每个线程的堆栈大小,默认为1M。太小容易发生栈溢出 java.lang.StackOverflowError,比如大量递归调用
。
5)JVM其他常用参数
-XX:-OmitStackTraceInFastThrow
:频繁抛出的异常,JDK性能优化,不抛出堆栈信息。比如java.lang.NullPointerException异常,没有发现stack信息。使用 - 禁用该优化。
-XX:+HeapDumpOnOutOfMemoryError
:当发生OOM时,自动生成堆内存的快照。
-XX:HeapDumpPath=${path}
:将快到dump到指定路径。
当机器内存为4G时,jvm最多能使用3G内存,否则会出现大量swap,造成其他隐患。机器内存较小时,垃圾收集建议采用-XX:UseConcMarkSweepGCCMS
的垃圾收集器,当机器内存较大,建议采用–XX:+UseG1GCG1
的垃圾收集器堆内存分隔,并发回收
。
2,full gc优化实例
1)full gc 日志。
2018-06-05 19:55:37 系统发布
2018-06-05T19:58:49.010+0800: 11.666: [Full GC (Metadata GC Threshold) [PSYoungGen: 85801K->0K(491008K)] [ParOldGen: 91072K->80697K(1398272K)] 176874K->80697K(1889280K), [Metaspace: 20748K->20748K(1069056K)], 0.0946573 secs] [Times: user=0.32 sys=0.00, real=0.09 secs]
2018-06-05T19:58:51.295+0800: 13.951: [Full GC (Metadata GC Threshold) [PSYoungGen: 23280K->0K(427520K)] [ParOldGen: 80705K->67473K(1398272K)] 103986K->67473K(1825792K), [Metaspace: 34618K->34618K(1081344K)], 0.0756590 secs] [Times: user=0.16 sys=0.00, real=0.08 secs]
2018-06-05T19:59:00.786+0800: 23.442: [Full GC (Metadata GC Threshold) [PSYoungGen: 91611K->0K(541696K)] [ParOldGen: 67509K->139079K(1398272K)] 159120K->139079K(1939968K), [Metaspace: 58003K->58003K(1101824K)], 0.2371749 secs] [Times: user=0.71 sys=0.01, real=0.24 secs]
2018-06-06 18:22:29 系统发布
2018-06-06T18:25:53.480+0800: 11.917: [Full GC (Metadata GC Threshold) [PSYoungGen: 78570K->0K(481792K)] [ParOldGen: 95770K->74600K(1398272K)] 174341K->74600K(1880064K), [Metaspace: 20748K->20748K(1069056K)], 0.0983428 secs] [Times: user=0.30 sys=0.01, real=0.10 secs]
2018-06-06T18:25:55.796+0800: 14.232: [Full GC (Metadata GC Threshold) [PSYoungGen: 23229K->0K(418304K)] [ParOldGen: 74608K->67092K(1398272K)] 97837K->67092K(1816576K), [Metaspace: 34644K->34644K(1081344K)], 0.0894847 secs] [Times: user=0.26 sys=0.00, real=0.09 secs]
2018-06-06T18:26:16.305+0800: 34.742: [Full GC (Metadata GC Threshold) [PSYoungGen: 81613K->0K(552960K)] [ParOldGen: 67116K->129245K(1398272K)] 148729K->129245K(1951232K), [Metaspace: 58512K->58512K(1101824K)], 0.1918869 secs] [Times: user=0.54 sys=0.00, real=0.19 secs]
日志解释
现象:每次重启都发生几次full gc。Metadata GC Threshold
:metaspace达到阈值了,发生了full gc。
发生原因:JDK8,-XX:PermSize无效,默认的-XX:MetaspaceSize为21M
,XX:MaxMetaspaceSize最大metaspace大小。
//堆在full gc前后,年轻代从85801K降到0K;年老代从91072K降到80697K。
//整个堆从176874K降到80697K,堆的总大小1889280K。-XX:NewRatio默认值:2。堆默认比例划分:年轻代:年老代 = 1 : 2
[PSYoungGen: 85801K->0K(491008K)] [ParOldGen: 91072K->80697K(1398272K)] 176874K->80697K(1889280K)
//持久代(元空间)从20748K-20748K,没有变化,最大能使用的空间为1069m,因为设置了堆-Xms2048m -Xmx2048m。
[Metaspace: 20748K->20748K(1069056K)]]
//此次full gc耗时约0.095s
0.0946573 secs
//用户态耗时0.32s,系统态耗时0s,实际耗时0.09s。由于机器有4个核,所以user=0.32s 大约是 real=0.09的3~4倍。
//user+sys是CPU时间。
[Times: user=0.32 sys=0.00, real=0.09 secs]
3,Tomcat优化
1)编码相关。每个JVM启动时都初始化一个encoding。依赖于系统的locale,使用系统的locale指定,或者使用
-Dfile.encoding=UTF-8
-D参数指定环境变量。
Tomcat中conf/server.xml中的Connector连接器中配置URIEncoding="UTF-8"
,URI使用中文。tomcat-7.0.81以上,不能URI使用中文。Connector用于创建httpRequest和httpResponse等对象
2)Connector连接器的设置。bio、nio 和 apr,三种方式性能差别很大,apr 的性能最优, bio 的性能最差。
通过启动日志grep看当前类型,http-bio、http-nio、http-apr。
bio:一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源,并且tomcat默认最大线程数200,Tomcat7或以下默认使用。
NIO:可以通过少量的线程处理大量的请求,Tomcat8默认使用,Tomcat7必须修改Connector配置。
APR:Apache Portable Runtime,tomcat7和tomcat8都需要安装Apr相关包。配置参考https://www.jianshu.com/p/10a536340635
默认使用bio。
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
NIO( New Input/ Output)
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8443" />
性能最有则使用apr,需要安装api库。
maxThreads: tomcat使用多线程来处理请求,最大线程数,默认为200。
minSpareThreads:最小空闲线程数。
maxSpareThreads:最大空闲线程数。
URIEncoding:URL编码方式。
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="500" minSpareThreads="100" />
connectionTimeout:连接超时时间。
keepAliveTimeout:长连接超时时间。
enableLookups:设为false不返回域名,直接使用ip地址。
acceptCount:当前线程都被使用时,接收的排队请求数量。
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11AprProtocol"
executor="tomcatThreadPool"
enableLookups="false"
acceptCount="400"
connectionTimeout="30000"
keepAliveTimeout="60000"
minSpareThreads="100"
URIEncoding="UTF-8"
maxThreads="500"
maxHttpHeaderSize="65536"
redirectPort="8443" />
4,常见OOM
1)
java.lang.OutOfMemoryError: Java heap space
,JVM堆溢出。可以使用-Xmn -Xms -Xmx
等来手动设置堆大小。
2)java.lang.OutOfMemoryError: PermGen space
,JVM永久代溢出。比如载入太多class。可以手动设置MaxPermSize 或者MaxMetaspaceSize
。
3)java.lang.StackOverflowError
,JVM栈溢出。比如大量递归调用。可以手动设置-Xss
每个线程栈的大小,默认为1M。
4)可以使用ps aux | grep ${项目名},来查看当前运行jvm的各种参数设置。
./version.sh查看tomcat版本信息。