項目總結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/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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM