JVM参数与优化

1,JVM参数

官网:『https://docs.oracle.com/javase/10/jrockit-hotspot/command-line-options.htm#JRHMG127
1)HotSpot虚拟机有很多非稳定参数Unstable Options,以-XX开头的参数。
-XX:+<option> 开启option参数。
-XX:-<option> 关闭option参数。
-XX:<option>=<value> 将option参数设置成value值。
2)垃圾收集优化常用参数

image.png

-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:UseConcMarkSweepGC CMS的垃圾收集器,当机器内存较大,建议采用–XX:+UseG1GC G1的垃圾收集器堆内存分隔,并发回收

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版本信息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容