场景来源
客户现场有一套重要的业务系统,供业务同事进行使用,但是每连续运行10天都会出现问题,会造成程序慢响应,无响应情况,严重影响消费者、使用者的使用体验,经常得到业务同事反馈,所以配合研发对该问题进行查询。
该系统硬件服务器性能足够,但每个重启周期内内存都是缓慢上升,观察JVM使用率、系统内存使用率等均是持续上升,未发现有主动进行内存回收,初步怀疑为内存泄漏导致。
初识JVM虚拟机

JVM虚拟机的结构
Java虚拟机主要分为五大模块:
类装载器子系统 运行时数据区 执行引擎 本地方法接口 垃圾收集模块



常见的内存溢出
现象一:
java.lang.OutOfMemoryError: Java heap space
代码中可能存在大对象分配。
可能存在内存泄露,导致在多次GC之后,还是无法找到一块足够大的内存容纳当前对象。
检查是否存在大对象的分配,最有可能的是大数组分配。
如果没有找到明显的内存泄露,可以临时 -Xmx 加大堆内存。
还有一点容易被忽略,检查是否有大量的自定义的 Finalizable 对象,也有可能是框架内部提供的,考虑其存在的必要性。
现象二:
java.lang.OutOfMemoryError: PermGen spacejava.lang.OutOfMemoryError: Metaspace
在Java7之前,频繁的错误使用String.intern()方法 。
运行期间生成了大量的代理类,导致方法区被撑爆,无法卸载 。
应用长时间运行,没有重启。
检查是否永久代空间或者元空间设置的过小。
检查代码中是否存在大量的反射操作 。
dump之后通过mat检查是否存在大量由于反射生成的代理类。
现象三:
java.lang.OutOfMemoryError:GC overhead limit exceeded
检查项目中是否有大量的死循环或有使用大内存的代码,优化代码。
添加参数 -XX:-UseGCOverheadLimit 禁用这个检查,其实这个参数解决不了内存问题,只是把错误的信息延后,最终出现 java.lang.OutOfMemoryError: Java heap space。
现象四:
java.lang.OutOfMemoryError : unable to create new native Thread
出现这种异常,基本上都是创建的了大量的线程导致的,以前碰到过一次,通过jstack出来一共8000多个线程。
通过 -Xss 降低的每个线程栈大小的容量。
线程总数也受到系统空闲内存和操作系统的限制,检查是否该系统下有此限制:
/proc/sys/kernel/pid_max /proc/sys/kernel/thread-max maxuserprocess(ulimit -u) /proc/sys/vm/maxmapcount
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
java.lang.OutOfMemoryError: Out of swap space
swap 分区大小分配不足。
其他进程消耗了所有的内存。
其它服务进程可以选择性的拆分出去 。
加大swap分区大小,或者加大机器内存大小。
紧急处理方法

本文作者:臧二飞
本文来源:IT那活儿(上海新炬王翦团队)





