美文网首页
解决一般OOM的通用方法

解决一般OOM的通用方法

作者: 掩流年 | 来源:发表于2020-05-05 19:31 被阅读0次

堆溢出

问题一般是由于不断的创建对象,随着对象数量的增加,总容量初级到了最大堆容量限制后就会导致内存溢出异常。

1.处理方法:
通过参数 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/test 可以让虚拟机在出现内存溢出异常的时候,Dump出当前的内存堆转储快照以便分析。

解决这个内存区域的异常,常规的方式是通过内存映像分析工具堆Dump出来的堆转储快照进行分析。(内存映像分析工具可以使用Eclipse Memory Analyzer 下载地址:https://www.eclipse.org/mat/downloads.php

2.确认几点:

  • 1.到底是发生了内存泄漏还是内存溢出?
  • 2.确认内存中导致OOM的对象是否是必要的?

如果是内存泄漏,可进一步使用工具查看泄漏对象到GC Roots的引用链,找到泄漏对象的引用路径,与那些GC Roots相关联,导致无法回收他们。

如果不是内存泄漏
1)检查Java虚拟机的堆参数(-Xmx -Xms),看看是否有向上调整的空间。
2)检查对象生命周期是否过长,存储实际是否不合理,来减少内存消耗。

最佳实践
不使用的对象可以置为null。参照ArrayList的源码,remove()方法中,置对象为null,clear to let GC do its work

    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

3.特殊注意:

1)针对JDK8而言,增加了元空间概念,元空间在Java8中被移到Java堆中。所以一般而言,方法区中产生的OOM基本是与堆中类似。

例如Spring等一些框架中大量的使用了CGlib增加字节码,生成了大量的动态类。有时候破坏性的使用方式就会导致元空间内存即Java堆内存被占满导致内存溢出。

2)直接内存溢出
一个明显的特征是Heap Dump文件中不会有什么明显的异常情况。
通常可能引起的原因是,因为一个进程占用固定的内存大小,默认情况下,直接内存大小和堆内存大小分配相同,有时候手动分配堆内存,会压缩直接内存容量,像NIO操作会大量使用直接内存,可能导致 OOM。

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

《Java虚拟机规范》中描述了两种异常

  • 线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError
  • 虚拟机的栈内存允许动态扩展,当扩展容量无法申请到足够的内存,则抛出OutOfMemory。

由于HotSpot虚拟机默认不允许动态扩展,所以在日常开发中,栈空间一般不会发生OutOfMemory。

相关文章

网友评论

      本文标题:解决一般OOM的通用方法

      本文链接:https://www.haomeiwen.com/subject/xkiryhtx.html