OOM小总结

427 阅读2分钟

概述

  • 记录一下日常开发中可能会出现的OOM 情况和一些解决方案

1、堆空间OOM

java.lang.OutOfMemoryError: Java heap space
  • 产生原因
    • 存在一个非常大的对象,比如集合、数组这类东西,然后一直往里面添加东西
    • 内存泄漏问题,内存无法回收
  • 表现
    • GC 时间越来越长,运行越来越卡(还没有抛出异常的时候)
  • 解决方案
    • 在内存设置足够的情况下,重点是找到那个类存在问题,大概率是一直在 new 没有释放
    • 通过 jmap 指令导出当前堆的 dump,使用工具分析下里面对象的构成(jvisiom、mat)都可以
    • 那个对象占比最大的,去寻找那个类的使用流程

2、元空间OOM

java.lang.OutOfMemoryError: PermGen space
java.lang.OutOfMemoryError: Metaspace
  • JDK8 之后,原空间采用的是本地内存,内部存放的是类的数据信息
  • 产生原因:
    • 检查是否反射用的过多,由于反射的时候会动态生成字节码,有可能导致
    • 检查下动态代理是否存在问题,动态代理也会反向生成字节码,而后反射生成代理类
  • 表现:
    • 频繁的 full gc
  • 解决方案:
    • 同样去查找 dump 之后去查找是否存在大量的反射生成的代理类
    • 记住,类也是一种对象,就和上面的方法差不多了

3、虚拟机栈OOM

java.lang.OutOfMemoryError : unable to create new native Thread
  • 产生原因
    • 虚拟机栈是线程私有的,所有只需要线程足够多的时候,就会产生溢出
    • 无意中创建了大量的线程
  • 表现
    • 没啥表现,就是抛异常
  • 解决方案
    • 线程的地方尽量去采用线程池来写,防止出现大量线程
    • 递归创建线程的地方需要去重点排查下
    • 降低每个线程栈的大小 -Xss

4、直接内存OOM

  • 产生原因
    • 直接内存不在JVM中管理,是由操作系统直接管理的,所以在JVM中并不会抛出异常
    • 大概率是使用 NIO 这样一类,直接请求堆外内存的操作所导致的
  • 表现
    • 虚拟机宕机,但是 Dump 很正常,发现不出什么问题
  • 解决方案
    • 查找下代码中直接或者间接使用 NIO 的地方是否直接请求堆外内存没有释放