项目总结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/JVM\java_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