nohup java -jar 启动springboot项目时JVM参数调优

背景:

java version "1.8.0_11"
项目用springboot写的,以往启动都没有设置JVM参数,都是默认的。
今天遇到频繁FGC的情况,导致服务器CPU占用超级高,而且FGC并不能有效的回收对象内存。

1.ps查询对应进程:

[root@10-9-166-14 server]# ps aux|grep addition
root     22670 43.5  5.8 4734040 944636 ?      Sl   21:37  53:18 java -jar -server -Xms1g -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=30 -XX:+DisableExplicitGC -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStampsaddition031601.war
root     30282  0.0  0.0 103256   972 pts/2    S+   23:40   0:00 grep addition

2.jstat -gcutil (查看GC汇总信息),看下对应的堆内存各部分的使用量:

[root@ logs]# jstat -gcutil 15984
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
  0.00   0.00 100.00 100.00  55.48  79.70  72824 1046.497  1339 3559.981 4606.479

显示列名具体描述
S0年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E年轻代中Eden(伊甸园)已使用的占当前容量百分比
Oold代已使用的占当前容量百分比
M元数据空间使用比例
CCS压缩使用比例
YGC从应用程序启动到采样时年轻代中gc次数
YGCT从应用程序启动到采样时年轻代中gc所用时间(s)
FGC从应用程序启动到采样时old代(全gc)gc次数
FGCT从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT从应用程序启动到采样时gc用的总时间(s)

可以看到
年轻代Eden区和老年代的使用容量都是100%

补充个知识点:
大多数情况下,对象在新生代Eden区分配。(大对象会直接在老年代分配,使用参数进行设置)当Eden区分配足够的空间进行分配时,就会触发MinorGc(新生代GC)。将超过GC年龄的对象移动到老年代中。

大致就能断定是对象Eden区分配内存时容量不够触发了GC,而导致的GC停顿。但是由于新生代和老年代的使用都是100%而对象又全都在被使用。所以无法回收内存。导致一直GC,一直停顿。。。

3.jinfo查看进行相关JVM信息

VM Flags:
Non-default VM flags: -XX:ConcGCThreads=1 -XX:+DisableExplicitGC -XX:G1HeapRegionSize=1048576 -XX:G1MaxNewSizePercent=30 -XX:G1NewSizePercent=20 -XX:InitialHeapSize=1073741824 -XX:MarkStackSize=4194304 -XX:MaxGCPauseMillis=200 -XX:MaxHeapSize=1073741824 -XX:MaxNewSize=321912832 -XX:MinHeapDeltaBytes=1048576 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC 
Command line:  -Xms1g -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=30 -XX:+DisableExplicitGC -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

可以看到看到默认的VM参数中 新生代和老生代的内存都非常的小,导致了GC的频繁触发。而老生代过小则导致了还在使用的大对象占用所有老生代内存,而不能被回收.

所以,解决方式就是启动时指定新生代和老生代的大小。
增大内存,不让GC频繁触发,不让少部分的大对象就占用所有的老生代内存。

4.nohup启动时指定JVM参数

nohup java -jar -server -Xms1g -Xmx1g -XX:+UseG1GC  -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=30 -XX:+DisableExplicitGC -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/data/www/$project_name/online/logs/gc_log_8000.log  ***.war/jar > javaxxx.log &

-Xms1g: 最小内存最小
-Xmx1g: 最大内存最大
建议设置-Xms与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存.

-XX:+UseG1GC
指定使用G1(GC收集器)

-XX:MaxGCPauseMillis=200
最长的GC暂停时间,如果时间过长,会相应调整空间的大小(单位是毫秒)

-XX:+UnlockExperimentalJVMOptions
有些时候当设置一个特定的JVM参数时,JVM会在输出“Unrecognized VM option”后终止。如果发生了这种情况,你应该首先检查你是否输错了参数。然而,如果参数输入是正确的,并且JVM并不识别,或许需要设置-XX:+UnlockExperimentalVMOptions 来解锁参数

-XX:G1NewSizePercent=20
设置要用作年轻代大小最小值的堆百分比。默认值是 Java 堆的 5%

-XX:G1MaxNewSizePercent=30
设置要用作年轻代大小最大值的堆大小百分比。默认值是 Java 堆的 60%。

-XX:+DisableExplicitGC
关闭系统调用GC功能 System.gc() 默认会触发一次Full Gc

-XX:+PrintGC
打印GC

-XX:+PrintGCDetails
打印GC详细信息

-XX:+PrintGCTimeStamps
打印GC时间戳

-Xloggc:/data/www/$project_name/online/logs/gc_log_8000.log
GC日志路径

5.启动后使用jstat -gcutil <毫秒数> 查看进程GC过程

在这里插入图片描述
在新生代和老年代都调大之后,发现老年代的使用占比小了很多,之前一启动就占了70%左右

通过观察GC次数,和每一次GC之后新生代和老年代的内存使用率就能大概看出内存回收的效率。如果还是出现GC无法回收的话,就需要dump 快照进行分析了。。。

6.一份更详细的启动参数配置

nohup java -jar -server -Xms1G -Xmx1G -XX:+UseG1GC  -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=30 -XX:+DisableExplicitGC -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/$project_name/online/logs/oom-error_8000.log -Xloggc:/data/www/$project_name/online/logs/gc_log_8000.log  ***.jar   > ***.log &

比上面用的增加了在out of memory的情况下的内存dump,以及输出的out是哪里,这些如果不需要可以不用加。用上面的就行

-XX:+HeapDumpOnOutOfMemoryError
在out of memory的情况下的内存dump

-XX:HeapDumpPath=/data/www/$project_name/online/logs/oom-error_8000.log
指定out of memory错误输出地址

7.特别说明

-XX:MaxGCPauseMillis=200
最长的GC暂停时间,如果时间过长,会相应调整空间的大小(单位是毫秒)

这个参数在使用的使用要特别注意。如果系统的大对象比较多的话,不要设置这个。
设置了之后,会导致GC频繁系统卡顿。
我之前就设置了。。。最近发现系统变卡了。
比如1G内存,正常到了1G才开始回收,可能回收一次需要1s,但是由于设置了XX:MaxGCPauseMillis=200。可能导致使用到200MB或者更少的时候就开始触发回收,导致设置的大内存压根没有用到。

还有关于线上JVM异常的问题调优帖子。
tomcat7 session共享集群导致的FullGC问题

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值