尽管JVM已经自动帮你做了一些管理内存的工作,但是这不代表了JVM就不会出现问题,真实的情况总是各种各样,根据不同的环境,各种各样的问题暴漏出来,也不断的可以体现出 当前编写代码的能力吧。
出现问题,查找原因,解决问题,能力提升。一步一步来吧。
出现这个异常 的情况 是 JVM这个异常的情况是,JVM花了大量的时间在GC,JVM去GC本来是很正常的事,但是花大量的时间,这个大量的时间如果来定义呢,Sun官方对此的定义是:“并行/并发回收器在GC回收时间过长时会抛出OutOfMemroyError。过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存。用来避免内存过小造成应用不能正常工作“。
并不是所有的应用都要加这个配置的:
又比如说,一些 支付,交易,和钱有关的网站,可能某个业务使用了一个JVM本地的Queue,当这个检查 检测到当前JVM要挂,就可以把这个Queue里的数据 紧急的使用 MappedByteBuffer的force强制把(重要的业务队列)数据写入到存储设备,这样这些数据就不会丢,还可以接着处理,避免给用户带来不好的体验、影响。
出现了上面俩个问题 怎么解决才是头等大事,问题总要一步一步解决的
1 . :如果当前程序是 发布到测试环境的,可以给jvm添加如下2个参数,以便下次又出现这个错误了,可以有点数据依据 去分析 -XX:+HeapDumpOnOutOfMemoryError -XX:HeadDumpPath=yourpath
2 . : 如果JVM还存活,可以到处dump 就 用jmap -dump , 用MAT 分析 导出的内容 ,这样方式只是可以告诉你 当前堆空间中 存在了大量 哪些对象,通常 帮助很小。如果是一些byte[] String char boolean 这样的东西,一下也找不出个头绪来,也别急你还可以找一位大神,他叫 btrace(精通解决各种JVM疑难杂症),这一部分在别的文章里面 说明。
java.lang.OutOfMemoryError: PermGen Space
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类的对象实例的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理。
解决办法:设置 -XX:PermSize=128M 就可以了,128M可以存放很多类信息了,不够再调.
java.lang.OutOfMemoryError: Unable to create new native thread
出现了这个异常,首先执行2个命令(Linux):
# ps -eLf | grep java -c 280 # ulimit -u 30475
还有一种情况(来自网上)是:
内存也空闲,但仍然创建不了,这有可能是由于在2.6.18/32内核上kernel.pid_max默认的32768造成的,这个值其实直接限制了最多能创建的线程数就是32768(即使ulimit -u的值比这大也没用)。
还有一种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来回收(到底设置成多大应用可以自己调整)。
jmap -heap <pid>
jstat -gcutil <pid> 10000 20 ,对比下看是不是有大量回收动作,是的话没准有内存泄露了
jmap -histo <pid>
参考:
http://bluedavy.me