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(伊甸园)已使用的占当前容量百分比
O old代已使用的占当前容量百分比
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过程

nohup java -jar 启动springboot项目时JVM参数调优_第1张图片
在新生代和老年代都调大之后,发现老年代的使用占比小了很多,之前一启动就占了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笔记,java,jvm,linux)