项目总结65:内存溢出OOM问题处理

项目总结65:内存溢出OOM问题处理

  OOM,即OutOfMemory,内存溢出,原因是:分配的太少;用的太多;用完没释放。理论上,JVM中除了程序计数器,堆内存,方法区,虚拟机方法栈,本地方法栈,都会出现OOM问题

常见的OOM情况有三种:

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

  2- java.lang.OutOfMemoryError: PermGen space/ Metaspace------>java永久代(元数据)溢出,即方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize/MetaspaceSize=64m      -XX:MaxPermSize/MaxMetaspaceSize =256m的形式修改。另外,过多的常量也会导致方法区溢出。

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

问题处理

一、 OOM: Java heap space;

问题示例:

    public static void main(String[] args) {
        //1- 堆内存溢出
        List<OOMObject> list = new ArrayList<>();
        int i = 0;
        while (true){
            list.add(new OOMObject());
            System.out.println(++i);
        }
    }
日志:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:/WORK/JVMjava_pid22096.hprof ...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3210)
    at java.util.Arrays.copyOf(Arrays.java:3181)
    at java.util.ArrayList.grow(ArrayList.java:261)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
    at java.util.ArrayList.add(ArrayList.java:458)
    at jvm.OOMTest.main(OOMTest.java:21)

解决方案:

1- 设置虚拟机运行参数,打印日志

-server -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/WORK/JVM

其中 -Xms20m -Xmx20m,是故意减少对内存,暴露问题;

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/WORK/JVM;将OOM异常体脂打印到D:/WORK/JVM文件夹下,生成的文件如下:

 2- 使用jprofile软件打开hprof文件,如下图,分析问题原因;发现OOMObject对象被创建了81W次,导致内存溢出;

3- 对症下药

三、 StackOverflowError 异常

示例

    public static void main(String[] args) {
        //2- 栈溢出
        recursion(0);

    }

    static int recursion(int num){
        if(num == 0){
            System.out.println(num);
            return recursion(num);
        }
        return 0;
    }
}
日志如下:
Exception in thread "main" java.lang.StackOverflowError
    at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
    at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
    at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
    at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
    at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
    at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
    at java.io.PrintStream.write(PrintStream.java:526)
    at java.io.PrintStream.print(PrintStream.java:597)
    at java.io.PrintStream.println(PrintStream.java:736)
    at jvm.OOMTest.recursion(OOMTest.java:31)
    at jvm.OOMTest.recursion(OOMTest.java:32)

解决方案:根据程序的.out日志文件(比如tomcat的catalina.out文件),排查问题出现在在哪里

END

原文地址:https://www.cnblogs.com/wobuchifanqie/p/13132560.html