java.lang.OutOfMemoryError: PermGen Space,当碰到这个现象时,可以通过调整permgen size来试试,如果放大了一点后还是不断的消耗,则可以通过btrace来跟踪下装载class的现象,脚本类似如下:
?
1
2
3
4
5
6
7
8
9
10
11
|
import static com.sun.btrace.BTraceUtils.*; import com.sun.btrace.annotations.*; @BTrace public class Trace{ @OnMethod( clazz="java.lang.ClassLoader", method="defineClass" ) public static void traceExecute(){ jstack(); } } |
还有一种OOM是native OOM,就是物理内存被耗光,对于这种现象,解决起来会麻烦一些,从经验上来说,Native OOM有很大概率是由于错误使用Deflater/Inflater造成的,所以在碰到这类现象时,可以先用btrace跟进下看看使用了Deflater/Inflater的有没有显式去调用end方法;另外一种常见的原因是使用Direct ByteBuffer的场景(例如NIO框架等),如使用了Direct ByteBuffer的对象是比较长存活的,当其被转到旧生代后,在fgc没触发前,其实其占用的JVM堆外内存是不会被释放的,在这种情况下,可以做的一个尝试是先强制执行几次fgc(jmap -histo:live),然后看看堆外内存的使用是不是下降了,如果下降了则说明是这个问题,对于这类问题,可以用的一个解决方案是增加一个启动参数:-XX:MaxDirectMemorySize=500m来实现当Direct ByteBuffer使用到500m后主动触发fgc来回收(到底设置成多大应用可以自己调整)。
如上面两招都没用,则需要挂上google perf-tools来跟踪下看看到底是哪里在malloc,不过这里看到的是c堆栈上的东西,因此需要自己想办法根据这个对应到java的代码上去。
关于native OOM,这篇文章里有一些具体排查的case。
除了OOM外,还有可能会碰到GC频繁的问题(有很多同学会问我,到底什么算频繁,我觉得基本上如果每隔10s或更短时间就来一次cms gc或full gc才算得上吧)。
GC频繁的现象出现时,如果发现cms gc或full gc后,存活的对象始终很多,这种情况下可以通过jmap -dump来获取下内存dump文件,然后通过MAT/btrace来定位到具体的原因。
如cms gc或full gc频繁,但触发时old还有空闲空间,这种情况下有可能会是由于悲观策略造成,具体可以看看这篇文章里的几个cases,这种情况下通常的解决方法可以是调大old或减小young。
如不是悲观策略造成的,对于采用cms gc的情况,还有可能是cms gc的碎片问题造成的,这种情况下可以通过强制执行下jmap -histo:live来触发fgc,不过悲催的是cms gc的碎片问题是无解的,暂时只能靠强制触发fgc等来避免在高峰期时出现问题。
对于cms gc而言,还有可能会出现promotion failed或concurrent mode failure问题,具体也可以看看上面那篇文章的cases。
Java进程crash或退出
Java进程crash或无故退出也是会碰到的现象,对于进程crash,默认情况下jdk会生成hs_err[pid].log的文件,core dump打开的话也会生成core dump文件,当进程crash发生时,可以先看看hs_err[pid].log,如没找到此文件,但有core dump文件,有可能的原因是代码中出现了无限递归或死循环,可通过jstack
原文转自:http://bluedavy.me/?p=445