OOM异常处理

文章目录

  • OOM异常处理
    • 思路
    • 一、Java堆溢出
      • 1、为什么会溢出?
      • 2、怎么解决?
    • 二、虚拟机栈和本地方法栈溢出
      • 1、为什么内存溢出?
      • 2、解决办法
    • 三、方法区和运行时常量池溢出
      • 1、为什么溢出?
    • 四、直接内存溢出

OOM异常处理

思路

  1. 在运行的时候设置JVM参数,使其Dump出内存异常信息, -XX:+HeapDumpOnOutOfMemoryError,当出现OOM异常的时候,我们就可以看到一场JVM打印的异常信息
  2. 通过内存映像分析工具(Eclipse Memory Analyzer)对Dump出来的内存转储快照进行分析
    1. 内存泄漏(Memory Leak)
    2. 内存溢出(Memory Overflow)
  3. 确定是哪种情况之后
    • 如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链,看看对象时通过怎样的路径与GC Roots相关联导致垃圾收集器无法自动回收他们,掌握了泄露对象的类型信息以及GC Roots引用链信息,就可以比较准确的定位泄漏的位置。
    • 如果不存在泄漏,就说明这些对象都是应该存活的,但是内存不够大。这时候就需要调整堆内存的大小,对比机器物理内存看看堆内存能否相应的调大一点,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

一、Java堆溢出

1、为什么会溢出?

堆是用来存储对象的,如果创建了大量的对象且这些对象得不到及时的回收就会造成内存占满,抛出OOM

2、怎么解决?

  • 设置JVM参数,Dump出当前的内存堆转储快照
  • 解决办法见思路

二、虚拟机栈和本地方法栈溢出

1、为什么内存溢出?

  • 对单个线程来说:HotSpot将两个栈合二为一,栈里面存储的是栈帧,只有当栈帧不断压入栈(函数递归)就会栈溢出。或者一个方法的变量太多导致栈帧太大,是的栈很快溢出StackOverflowError
  • 内存溢出:就是栈的数量太多了,也就是说创建的线程数量太多了,导致OOM

2、解决办法

  • 单线程来说:避免栈溢出

    • 1、找到递归函数,减少递归次数
    • 2、减少函数本地变量个数以及大小,相应的缩小栈帧的大小
    • 3、通过-Xss命令来扩大栈内存容量
  • 多线程造成的OOM

    • 1、减少线程创建数量,优先使用线程池
    • 2、如果是在不能减少线程,可以适当的减少虚拟机栈的内存来增加可容纳的线程数

三、方法区和运行时常量池溢出

1、为什么溢出?

  • 方法区存放的是类信息和运行时常量池

  • 如果创建大量的类(因为类的回收要求比较严格,所以一旦创建大量的类,得不到及时回收就会内存溢出)

    • 在项目中使用动态代理CGlib技术会生成大量的类,很多动态语言都是这么实现的
    • 因为类加载机制,不同的加载器加载出的同一个类,JVM会认为不同且都保留。
  • 如果创建大量的常量且放入常量池

    • String类中的internal()方法就是一个Native方法,它的作用是:如果字符串常量池中已经包含一个String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

四、直接内存溢出

  • DirectMemory容量可以通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值(-Xmx指定)一样。
  • 虽然使用DirectByteBuffer分配内存也会抛出内存溢出异常,但它是并没有真正向操作系统申请分配内存,而是通过计算得知内存无法分配,手动抛出的内存异常。

你可能感兴趣的:(JVM虚拟机)