java version "1.8.0_11"
项目用springboot写的,以往启动都没有设置JVM参数,都是默认的。
今天遇到频繁FGC的情况,导致服务器CPU占用超级高,而且FGC并不能有效的回收对象内存。
[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
[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,一直停顿。。。
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频繁触发,不让少部分的大对象就占用所有的老生代内存。
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日志路径
在新生代和老年代都调大之后,发现老年代的使用占比小了很多,之前一启动就占了70%左右
通过观察GC次数,和每一次GC之后新生代和老年代的内存使用率就能大概看出内存回收的效率。如果还是出现GC无法回收的话,就需要dump 快照进行分析了。。。
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错误输出地址
-XX:MaxGCPauseMillis=200
最长的GC暂停时间,如果时间过长,会相应调整空间的大小(单位是毫秒)
这个参数在使用的使用要特别注意。如果系统的大对象比较多的话,不要设置这个。
设置了之后,会导致GC频繁系统卡顿。
我之前就设置了。。。最近发现系统变卡了。
比如1G内存,正常到了1G才开始回收,可能回收一次需要1s,但是由于设置了XX:MaxGCPauseMillis=200。可能导致使用到200MB或者更少的时候就开始触发回收,导致设置的大内存压根没有用到。
如果有帮助,点个赞啊亲!