OOM问题排查及定位

1、什么是OOM

        程序中需要的内存大于JVM分配的内存空间,OOM后过就是程序崩溃,通俗理解为程序内存过大,虚拟机无法满足而自杀。

2、导致OOM的原因

        2.1、虚拟机分配的内存太少了,一般可通过启动时的JVM参数指定;

        2.2、应用用的太多了,而且用完不释放,浪费了。这个会造成内存泄漏或内存溢出;

        内存泄漏:申请使用完的内存没有释放,导致虚拟机不能再次使用。

        内存溢出:申请的内存超过了JVM能提供的最大内存。

3、常见的内存溢出

java.lang.OutOfMemoryError: Java heap space

        java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。

java.lang.OutOfMemoryError: PermGen space 或 java.lang.OutOfMemoryError:MetaSpace

        java方法区,(java8 元空间)溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出。

java.lang.StackOverflowError

        不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。

4、排查手段

        一般手段是:先通过内存映像工具对Dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏还是内存溢出。

4.1、如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链。这样就能够找到泄漏的对象是通过怎么样的路径与GC Roots相关联的导致垃圾回收机制无法将其回收。掌握了泄漏对象的类信息和GC Roots引用链的信息,就可以比较准确地定位泄漏代码的位置。

4.2、如果不存在泄漏,那么就是内存中的对象确实必须存活着,那么此时就需要通过虚拟机的堆参数( -Xmx和-Xms)来适当调大参数;从代码上检查是否存在某些对象存活时间过长、持有时间过长的情况,尝试减少运行时内存的消耗。

5、排查命令

top 进程号:查看CPU占用高的进程

top -H -p 进程号:查看CPU占用高的线程

print "%x\n" 线程号:查看线程ID的16进制

jstack 16进制的线程ID | grep 现成ID -A 80 :定位线程在做什么从而排查问题

6、排查工具

arthas:简介 | arthas

你可能感兴趣的:(jvm,java,开发语言)