troubleshoot之:分析OutOfMemoryError異常


簡介

java.lang.OutOfMemoryError應該java應用程序中非常常見的一個的錯誤了。

那么OutOfMemoryError產生的原因是什么呢?我們怎么去查找相應的錯誤呢?一起來看看吧。

OutOfMemoryError

先看一下OutOfMemoryError的定義,OutOfMemoryError繼承自
VirtualMachineError,它是Error的一種,表示的是應用程序無法處理的異常,一般情況下會導致虛擬機退出。

public class OutOfMemoryError extends VirtualMachineError {
    @java.io.Serial
    private static final long serialVersionUID = 8228564086184010517L;

    /**
     * Constructs an {@code OutOfMemoryError} with no detail message.
     */
    public OutOfMemoryError() {
        super();
    }

    /**
     * Constructs an {@code OutOfMemoryError} with the specified
     * detail message.
     *
     * @param   s   the detail message.
     */
    public OutOfMemoryError(String s) {
        super(s);
    }
}

一般情形下,如果heap沒有更多的空間來分配對象,就會拋出OutOfMemoryError。

還有一種情況是沒有足夠的native memory來加載java class。

在極少數情況下,如果花費大量時間進行垃圾回收並且只釋放了很少的內存,也有可能引發java.lang.OutOfMemoryError。

如果發生OutOfMemoryError,同時會輸出相應的stack trace信息。

下面我們分析一下各個不同的OutOfMemoryError。

java.lang.OutOfMemoryError: Java heap space

Java heap space表示的是新對象不能在java heap中分配。

如果遇到這種問題,第一個要想到的解決方法就是去看配置的heap大小是不是太小了。

當然,如果是一個一直都在運行的程序,突然間發生這種問題就要警惕了。因為有可能會存在潛在的內存泄露。需要進一步分析。

還有一種情況,如果java對象實現了finalize方法,那么該對象在垃圾回收的時候並不會立刻被回收。而是放到一個finalization隊列中。

這個隊列會由終結器守護線程來執行。如果終結器守護線程的執行速度比對象放入終結器隊列中的速度要慢的話,就會導致java對象不能被及時回收。

如果應用程序創建了高優先級的線程,那么高優先級的線程將有可能會導致對象被放入finalization隊列的速度比終結器守護線程的處理速度慢。

java.lang.OutOfMemoryError: GC Overhead limit exceeded

GC overhead limit exceeded表示的是GC一直都在運行,從而導致java程序本身執行非常慢。

如果一個java程序98%的時間都在做GC操作,但是只恢復了2%的heap空間,並且持續5次。那么java.lang.OutOfMemoryError將會被拋出。

可以使用下面的參數來關閉這個功能。

-XX:-UseGCOverheadLimit

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

這個錯誤的意思是,要分配的array比heap size大。

比如說設置的最大heap大小是256M,但是分配了一個300M的數組,就會出現這個問題。

java.lang.OutOfMemoryError: Metaspace

從JDK8之后,Metaspace已經移到了java的本地內存空間中。如果Metaspace超出了限制的大小,那么java.lang.OutOfMemoryError也會拋出。

Metaspace的空間大小可以通過MaxMetaSpaceSize來設置。

java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?

當本地堆分配失敗並且本地堆即將耗盡的時候就會報這個異常。

java.lang.OutOfMemoryError: Compressed class space

在64位的平台,對象指針可以用32位表示(對象指針壓縮)。

對象指針壓縮可以通過:

UseCompressedClassPointers

來啟用,默認這個參數是開啟的。

我們可以使用CompressedClassSpaceSize來設置指針壓縮空間的大小。

注意,只有klass元信息是存放在CompressedClassSpaceSize設置的空間中的,而其他的元信息都是存放在Metaspace中的。

OutOfMemoryError: reason stack_trace_with_native_method

這個錯誤表示本地方法遇到分配失敗。

遇到這種問題可能需要操作系統的本地調試工具來解決。

總結

本文介紹了OutOfMemoryError的不同種類,希望大家能夠有所收獲。

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/jvm-outofmemoryerror-analysis/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等着您!


免責聲明!

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



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