Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
GC回收时间过长时会抛出OutOfMemoryError。过长的定义是,超过98%的时间用来做GC,并且回收了不到2%的堆内存
连续多次GC都只回收了不到2%的极端情况下才会抛出。假如不抛出GC overhead limit错误会发生什么情况呢?
那就是GC清理的这么点内存很快会再次填满,迫使GC再次执行,这样就形成恶性循环,
CPU使用率一直是100%,而GC却没有任何成果。
这其实是jvm预判将会发生OutOfMemery异常,就提早抛出这个异常。并不代表jvm没有内存空间了。
于是在启动参数里,加入-XX:-UseGCOverheadLimit参数,关闭jvm的预判功能。
解析
二、-Djava.security.egd=file:/dev/./urandomSecureRandom在java各种组件中使用广泛,可以可靠的产生随机数。但在大量产生随机数的场景下,性能会较低。这时可以使用"-Djava.security.egd=file:/dev/./urandom"加快随机数产生过程。
解析
三、-Djava.io.tmpdir=/Data导入数据的时候,上传的excel会在服务器上生成一个临时文件,而这个临时文件都在 tomcat 的安装目录下,如果上传次数比较多的话,就会导致tomcat安装目录下有多个临时的excel文件,很不合理也不美观。这个问题主要是因为java.io.tmpdir这个系统配置没指定好,可以用它指定要保存的目录。
解析
四、-XX:+PrintGC、-verbose:gc 4.1 -XX:+PrintGC-XX:+PrintGC可以打印GC的简要信息
[GC 4790K->374K(15872K), 0.0001606 secs]
[GC 4790K->374K(15872K), 0.0001474 secs]
[GC 4790K->374K(15872K), 0.0001563 secs]
[GC 4790K->374K(15872K), 0.0001682 secs]
-XX:+PrintGC 与 -verbose:gc 是一样的,可以认为-verbose:gc 是 -XX:+PrintGC的别名.-XX:+PrintGCDetails 在启动脚本可以自动开启-XX:+PrintGC , 如果在命令行使用jinfo开启的话,不会自动开启-XX:+PrintGC
4.1 java -verbose:gc中参数-verbose:gc 表示输出虚拟机中GC的详细情况.
[Full GC 168K->97K(1984K), 0.0253873 secs]
解读如下:
箭头前后的数据168K和97K分别表示垃圾收集GC前后所有存活对象使用的内存容量,说明有168K-97K=71K的对象容量被回收,括号内的数据1984K为堆内存的总容量,收集所需要的时间是0.0253873秒(这个时间在每次执行的时候会有所不同)
解析、解析
五、-XX:+PrintGCDetails打印GC详细信息
n-XX:+PrintGCDetails的输出
–Heap
– def new generation total 13824K, used 11223K [0x27e80000, 0x28d80000, 0x28d80000)
– eden space 12288K, 91% used [0x27e80000, 0x28975f20, 0x28a80000)
– from space 1536K, 0% used [0x28a80000, 0x28a80000, 0x28c00000)
– to space 1536K, 0% used [0x28c00000, 0x28c00000, 0x28d80000)
– tenured generation total 5120K, used 0K [0x28d80000, 0x29280000, 0x34680000)
– the space 5120K, 0% used [0x28d80000, 0x28d80000, 0x28d80200, 0x29280000)
– compacting perm gen total 12288K, used 142K [0x34680000, 0x35280000, 0x38680000)
– the space 12288K, 1% used [0x34680000, 0x346a3a90, 0x346a3c00, 0x35280000)
– ro space 10240K, 44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000)
– rw space 12288K, 52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000)
解析
六、-XX:+PrintGCDateStamps-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
解析
七、-Xloggc 7.1 -Xloggc-Xloggc:tomcat_gc.log
指定GC log的位置,以文件输出 帮助开发人员分析问题
-XX:UseGCLogFileRotation
-XX:NumberOfGCLogFiles
-XX:GCLogFileSize
这次分享了3个设置滚动记录GC日志的参数
通过参数-Xloggc:xxx可指定GC日志文件路径
普通情况下,GC日志文件内容会不断积累,进程重启后日志文件会被覆盖
这次分享的3个参数在设置-Xloggc参数的前提下有效
7.2 -XX:UseGCLogFileRotationEnabled GC log rotation, requires -Xloggc.
打开或关闭GC日志滚动记录功能,要求必须设置 -Xloggc参数
7.3 -XX:NumberOfGCLogFilesSet the number of files to use when rotating logs, must be >= 1.
The rotated log files will use the following naming scheme, .0, .1, ..., .n-1.
设置滚动日志文件的个数,必须大于1
日志文件命名策略是,.0, .1, ..., .n-1,其中n是该参数的值
7.4 -XX:GCLogFileSizeThe size of the log file at which point the log will be rotated, must be >= 8K.
设置滚动日志文件的大小,必须大于8k
当前写日志文件大小超过该参数值时,日志将写入下一个文件
注,GC日志最好不滚动输出,因为之前的关键日志可能会被冲掉,日志写入同一个文件更方便分析
解析、解析
八、-XX:+PrintGCApplicationConcurrentTime打印应用执行的时间
打印每次GC时程序运行的时间,当GC后时间置为0.
解析
九、-XX:+PrintGCApplicationStoppedTime打印应用被暂停的时间
每次GC使程序停顿的时间
解析、JVM性能调优参数摘要
十、-XX:+PrintAdaptiveSizePolicy 10.1 AdaptiveSizePolicy(自适应大小策略) :JDK 1.8 默认使用 UseParallelGC 垃圾回收器,该垃圾回收器默认启动了 AdaptiveSizePolicy,会根据GC的情况自动计算 Eden、From 和 To 区的大小;
10.2 配置:开启:-XX:+UseAdaptiveSizePolicy 关闭:-XX:-UseAdaptiveSizePolicy
10.3 注意事项:- 在 JDK 1.8 中,如果使用 CMS,无论 UseAdaptiveSizePolicy 如何设置,都会将 UseAdaptiveSizePolicy 设置为 false;不过不同版本的JDK存在差异;
- UseAdaptiveSizePolicy不要和SurvivorRatio参数显示设置搭配使用,一起使用会导致参数失效;
- 由于AdaptiveSizePolicy会动态调整 Eden、Survivor 的大小,有些情况存在Survivor 被自动调为很小,比如十几MB甚至几MB的可能,这个时候YGC回收掉 Eden区后,还存活的对象进入Survivor 装不下,就会直接晋升到老年代,导致老年代占用空间逐渐增加,从而触发FULL GC,如果一次FULL GC的耗时很长(比如到达几百毫秒),那么在要求高响应的系统就是不可取的。
解析、解析
十一、-XX:ReservedCodeCacheSize一个经常被忽视的JVM内存区域是"code cache",用来存储方法编译后的native code。平常该区域不会存在性能问题,但是一旦发生问题都是灾难性的。当code cache区域用尽时,JVM会给出警告信息然后切换到"interpreted-only "模式,该模式下停止JIT编译器,字节码不能编译成native code,性能急速下降。可以通过设置-XX:InitialCodeCacheSize and -XX:ReservedCodeCacheSize来调整code cache区域大小。
解析
十二、-XX:+PrintFlagsFinal-XX:+PrintFlagsInitial 是打印所有的默认参数设置
-XX:+PrintFlagsFinal 是打印最终值,如果某个默认值被新值覆盖,显示新值
-XX:+PrintCommandLineFlags 是打印那些被新值覆盖的项
十三、-XX:+UnlockCommercialFeatures -XX:+FlightRecorder
Java Flight Recorder是JVM内置的记录引擎,能收集JVM和Java应用数据,帮助开发者诊断分析Java应用。
Java Flight Recorder(JFR)是一款商业软件,台式机/笔记本电脑上可免费使用,对开发测试及生产环境的程序进行评估。
生产服务器使用JFR ,需要商业许可证。
开销约2%左右,可在生产环境中开启,除非对性能或延迟非常敏感。
记录类型
JFR飞行记录分两种:连续记录、分析记录。
JDK 8u40发布前,JVM须开启标志位:
-XX:+UnlockCommercialFeatures
-XX:FlightRecorder
十四、-XX:+HeapDumpOnOutOfMemoryError
当堆内存空间溢出时,输出堆的内存快照
配合参数:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/export/home/tomcat/logs/...
触发条件:
java.lang.OutOfMemo-ryError: Java heap space
也就是说当发生OutOfMemoryError错误时,才能触发-XX:HeapDumpOnOutOfMemoryError 输出到-XX:HeapDumpPath指定位置
解析
十五、 -Xss512kJava程序中,每个线程都有自己的Stack Space。这个Stack Space不是来自Heap的分配。所以Stack Space的大小不会受到-Xmx和-Xms的影响,这2个JVM参数仅仅是影响Heap的大小。 Stack Space用来做方法的递归调用时压入Stack Frame。所以当递归调用太深的时候,就有可能耗尽Stack Space,爆出StackOverflow的错误。Stack Space的大小随着OS,JVM以及环境变量的大小而发生变化。一般说来默认的大小是512K。在64位的系统中,这个Stack Space值会更大。一般说来,Stack Space为128K是够用的。这时你说需要做的就是观察。如果你的程序没有爆出StackOverflow的错误,可以使用-Xss来调整Stack Space的大小为128K。(eg:-Xss128K)
解析
十六、-Dio.netty.leakDetection.level=advanced -Dio.netty.leakDetection.targetRecords=40
-Dio.netty.leakDetectionLevel=advanced
-Dio.netty.leakDetection.targetRecords=40
Netty的内存泄漏检测分为四个级别:
- DISABLED - 完成禁止检测内存泄漏,这个是不推荐。
- SIMPLE - 如果buffer中出现1%的内存泄漏,打印错误日志,就是上面那样。但是日志是看不到详细在什么位置出现了内存泄漏。鉴于性能考虑,这个是在生产环境中默认使用。
- ADVANCED - 如果buffer的1%出现内存泄漏,打印错误,并且输出详细的内存泄漏信息。
- PARANOID - 这个和ADVANCED输出的内容是一样的,但它会对每一次请求的buffer做检查。很适用于调试和单元测试。
在介绍内存泄漏检测相关类时,
我们介绍过DefaultResourceLeak
提供了record
方法记录用户的调用轨迹,如果当前保存的调用轨迹记录数Record
大于参数io.netty.leakDetection.targetRecords
配置的值,那么会以一定的概率(1/2^n)删除头结点之后再加入新的记录,当然也有可能不删除头结点直接新增新的记录。该参数的默认为4。
解析、解析1