java常見內存溢出(OOM)

jvm內存區域

  1. 程序計數器
    一塊很小的內存空間,做用是當前線程所執行的字節碼的行號指示器。
  2. java棧
    與程序計數器同樣,java棧(虛擬機棧)也是線程私有的,其生命週期與線程相同。一般存放基本數據類型,對象引用(一個指向對象起始地址的引用指針或一個表明對象的句柄),reeturnAddress類型(指向一條字節碼指令的地址)java

    棧區域有兩種異常類型:若是線程請求的棧深度大於虛擬機所容許的深度,將拋StrackOverflowError異常;若是虛擬機棧能夠動態擴展(大部分虛擬機均可動態擴展),當擴展時沒法申請到足夠的內存時會拋出OutOfMemoryError異常。hexo

  3. 本地方法棧
    與虛擬機棧做用很類似,區別是虛擬機棧爲虛擬機執行java方法服務,而本地方法棧則是爲虛擬機用到的Native方法服務。和虛擬機棧同樣可能拋出StackOverflowError和OutOfMemoryError異常。
  4. java堆
    java Heap是jvm所管理的內存中最大的區域。JavaHeap是被全部線程共享的一塊內存區域,在虛擬機啓動時建立。主要存放對象實例。JavaHeap是垃圾收集器管理的主要區域,其可細分爲新生代和老年代。若是在堆中沒有內存完成實例分配,而且也沒法再擴展時,會拋出OutOfMemoryError異常。
  5. 方法區
    與javaHeap同樣是各個線程共享的內存區域,用於存放已被虛擬機加載的類信息、常量、靜態變量、及時編譯器編譯後的代碼等數據。當方法區沒法知足內存分配的需求時,將拋出OutOfMemoryError異常。方法同時包含常據說的運行時常量池,用於存放編譯期生成的各類字面量和符號引用。
  6. 直接內存
    直接內存並非虛擬機運行時數據區的一部分,也不是java虛擬機規範中定義的內存區域,是jvm外部的內存區域,這部分區域也可能致使OutOfMemoryError異常。

jvm參數

-Xss(StackSpace)棧空間jvm

-Xms ,-Xmx(heap memory space)堆空間:Heap是你們最爲熟悉的區域,他是jvm用來存儲對象實例的區域,Heap在32位的系統中最大爲2G,其大小經過-Xms和-Xmx來控制,-Xms爲jvm啓動時申請的最小Heap內存,默認爲物理內存的1/64,但小於1G,-Xmx爲jvm可申請的最大的Heap內存,默認爲物理內存的1/4,通常也小於1G,默認當空餘堆內存小於40%時,jvm會最大Heap的大小到-Xmx指定大小,可經過-XX:MinHeapFreeRatio來指定這個比例,當空餘堆內存大於70%時,JVM會將Heap的大小往-Xms指定的大小調整,可經過-XX:MaxHeapFreeRatio來指定這個比例,但一般爲了不頻繁調整HeapSize的大小,將-Xms和-Xmx的值設爲相同。工具

-XX:PermSize -XX:MaxPermSize:方法區持久代大小:方法區域也是全局共享的,在必定的條件下它也會被 GC,當方法區域須要使用的內存超過其容許的大小時,會拋出 OutOfMemory的錯誤信息。spa

常見內存溢出錯誤解決辦法

  1. OutOfMemoryError異常
    除了程序計數器外,虛擬機內存的其餘幾個運行時區域都有發生OutOfMemoryError(OOM)異常的可能,線程

    Java Heap 溢出指針

    通常的異常信息:java.lang.OutOfMemoryError:Java heap spacess對象

    java堆用於存儲對象實例,咱們只要不斷的建立對象,而且保證GC Roots到對象之間有可達路徑來避免垃圾回收機制清除這些對象,就會在對象數量達到最大堆容量限制後產生內存溢出異常。生命週期

    出現這種異常,通常手段是先經過內存映像分析工具(如Eclipse Memory Analyzer)對dump出來的堆轉存快照進行分析,重點是確認內存中的對象是不是必要的,先分清是由於內存泄漏(Memory Leak)仍是內存溢出(Memory Overflow)。ip

    若是是內存泄漏,可進一步經過工具查看泄漏對象到GC Roots的引用鏈。因而就能找到泄漏對象時經過怎樣的路徑與GC Roots相關聯並致使垃圾收集器沒法自動回收。

    若是不存在泄漏,那就應該檢查虛擬機的參數(-Xmx與-Xms)的設置是否適當。

  2. 虛擬機棧和本地方法棧溢出
    若是線程請求的棧深度大於虛擬機所容許的最大深度,將拋出StackOverflowError異常。

    若是虛擬機在擴展棧時沒法申請到足夠的內存空間,則拋出OutOfMemoryError異常

    這裏須要注意當棧的大小越大可分配的線程數就越少。

  3. 運行時常量池溢出
    異常信息:java.lang.OutOfMemoryError:PermGen space

    若是要向運行時常量池中添加內容,最簡單的作法就是使用String.intern()這個Native方法。該方法的做用是:若是池中已經包含一個等於此String的字符串,則返回表明池中這個字符串的String對象;不然,將此String對象包含的字符串添加到常量池中,而且返回此String對象的引用。因爲常量池分配在方法區內,咱們能夠經過-XX:PermSize和-XX:MaxPermSize限制方法區的大小,從而間接限制其中常量池的容量。

  4. 方法區溢出
    方法區用於存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。

    異常信息:java.lang.OutOfMemoryError:PermGen space

    方法區溢出也是一種常見的內存溢出異常,一個類若是要被垃圾收集器回收,斷定條件是很苛刻的。在常常動態生成大量Class的應用中,要特別注意這點。

參考

《深刻理解java虛擬機》

相關文章
相關標籤/搜索