1. 程式人生 > >異常、堆記憶體溢位、OOM的幾種情況

異常、堆記憶體溢位、OOM的幾種情況

1、堆記憶體溢位

【情況一】:
  java.lang.OutOfMemoryError: Java heap space:這種是java堆記憶體不夠,一個原因是真不夠,另一個原因是程式中有死迴圈;
  如果是java堆記憶體不夠的話,可以通過調整JVM下面的配置來解決:
  < jvm-arg>-Xms3062m < / jvm-arg>
  < jvm-arg>-Xmx3062m < / jvm-arg>
  
【情況二】
  java.lang.OutOfMemoryError: GC overhead limit exceeded
  【解釋】:JDK6新增錯誤型別,當GC為釋放很小空間佔用大量時間時丟擲;一般是因為堆太小,導致異常的原因,沒有足夠的記憶體。
  【解決方案】:
  1、檢視系統是否有使用大記憶體的程式碼或死迴圈;
  2、通過新增JVM配置,來限制使用記憶體:
  < jvm-arg>-XX:-UseGCOverheadLimit< /jvm-arg>
  
【情況三】:
  java.lang.OutOfMemoryError: PermGen space:這種是P區記憶體不夠,可通過調整JVM的配置:
  < jvm-arg>-XX:MaxPermSize=128m< /jvm-arg>
  < jvm-arg>-XXermSize=128m< /jvm-arg>
  【注】:
  JVM的Perm區主要用於存放Class和Meta資訊的,Class在被Loader時就會被放到PermGen space,這個區域成為年老代,GC在主程式執行期間不會對年老區進行清理,預設是64M大小,當程式需要載入的物件比較多時,超過64M就會報這部分記憶體溢位了,需要加大記憶體分配,一般128m足夠。
  
【情況四】:
  java.lang.OutOfMemoryError: Direct buffer memory
  調整-XX:MaxDirectMemorySize= 引數,如新增JVM配置:
  < jvm-arg>-XX:MaxDirectMemorySize=128m< /jvm-arg>
  
【情況五】:
  java.lang.OutOfMemoryError: unable to create new native thread
  【原因】:Stack空間不足以建立額外的執行緒,要麼是建立的執行緒過多,要麼是Stack空間確實小了。
  【解決】:由於JVM沒有提供引數設定總的stack空間大小,但可以設定單個執行緒棧的大小;而系統的使用者空間一共是3G,除了Text/Data/BSS /MemoryMapping幾個段之外,Heap和Stack空間的總量有限,是此消彼長的。因此遇到這個錯誤,可以通過兩個途徑解決:
  1.通過 -Xss啟動引數減少單個執行緒棧大小,這樣便能開更多執行緒(當然不能太小,太小會出現StackOverflowError);
  2.通過-Xms -Xmx 兩引數減少Heap大小,將記憶體讓給Stack(前提是保證Heap空間夠用)。
  
【情況六】:
  java.lang.StackOverflowError
  【原因】:這也記憶體溢位錯誤的一種,即執行緒棧的溢位,要麼是方法呼叫層次過多(比如存在無限遞迴呼叫),要麼是執行緒棧太小。
  【解決】:優化程式設計,減少方法呼叫層次;調整-Xss引數增加執行緒棧大小。

2、Java異常

這裡寫圖片描述

  1. Throwable
    Throwable是 Java 語言中所有錯誤或異常的超類。
    Throwable包含兩個子類: Error 和 Exception 。它們通常用於指示發生了異常情況。
    Throwable包含了其執行緒建立時執行緒執行堆疊的快照,它提供了printStackTrace()等介面用於獲取堆疊跟蹤資料等資訊。

  2. Exception
    Exception及其子類是 Throwable 的一種形式,它指出了合理的應用程式想要捕獲的條件。

  3. RuntimeException
    RuntimeException是那些可能在 Java 虛擬機器正常執行期間丟擲的異常的超類。
    編譯器不會檢查RuntimeException異常

    例如,除數為零時,丟擲ArithmeticException異常。RuntimeException是ArithmeticException的超類。當代碼發生除數為零的情況時,倘若既”沒有通過throws宣告丟擲ArithmeticException異常”,也”沒有通過try…catch…處理該異常”,也能通過編譯。這就是我們所說的”編譯器不會檢查RuntimeException異常”!
    如果程式碼會產生RuntimeException異常,則需要通過修改程式碼進行避免。 例如,若會發生除數為零的情況,則需要通過程式碼避免該情況的發生!

  4. Error
    和Exception一樣, Error也是Throwable的子類。 它用於指示合理的應用程式不應該試圖捕獲的嚴重問題

    ,大多數這樣的錯誤都是異常條件。
    和RuntimeException一樣, 編譯器也不會檢查Error

Java將可丟擲(Throwable)的結構分為三種類型: 被檢查的異常(Checked Exception),執行時異常(RuntimeException)和錯誤(Error)

(01) 執行時異常
定義 : RuntimeException及其子類都被稱為執行時異常。
特點 : Java編譯器不會檢查它。 也就是說,當程式中可能出現這類異常時,倘若既”沒有通過throws宣告丟擲它”,也”沒有用try-catch語句捕獲它”,還是會編譯通過。例如,除數為零時產生的ArithmeticException異常陣列越界時產生的IndexOutOfBoundsException異常,fail-fail機制產生的ConcurrentModificationException異常等,都屬於執行時異常。
雖然Java編譯器不會檢查執行時異常,但是我們也可以通過throws進行宣告丟擲,也可以通過try-catch對它進行捕獲處理。
如果產生執行時異常,則需要通過修改程式碼來進行避免。 例如,若會發生除數為零的情況,則需要通過程式碼避免該情況的發生!

(02) 被檢查的異常
定義 : Exception類本身,以及Exception的子類中除了”執行時異常”之外的其它子類都屬於被檢查異常。
特點 : Java編譯器會檢查它此類異常,要麼通過throws進行宣告丟擲,要麼通過try-catch進行捕獲處理,否則不能通過編譯。例如,CloneNotSupportedException就屬於被檢查異常。當通過clone()介面去克隆一個物件,而該物件對應的類沒有實現Cloneable介面,就會丟擲CloneNotSupportedException異常。
被檢查異常通常都是可以恢復的。

(03) 錯誤
定義 : Error類及其子類。
特點 : 和執行時異常一樣,編譯器也不會對錯誤進行檢查
當資源不足、約束失敗、或是其它程式無法繼續執行的條件發生時,就產生錯誤。程式本身無法修復這些錯誤的。例如,VirtualMachineError就屬於錯誤。
按照Java慣例,我們是不應該是實現任何新的Error子類的!

對於上面的3種結構,我們在丟擲異常或錯誤時,到底該哪一種?《Effective Java》中給出的建議是: 對於可以恢復的條件使用被檢查異常,對於程式錯誤使用執行時異常。

OOM

1, OutOfMemoryError異常

除了程式計數器外,虛擬機器記憶體的其他幾個執行時區域都有發生OutOfMemoryError(OOM)異常的可能,

Java Heap 溢位

一般的異常資訊:java.lang.OutOfMemoryError:Java heap spacess

java堆用於儲存物件例項,我們只要不斷的建立物件,並且保證GC Roots到物件之間有可達路徑來避免垃圾回收機制清除這些物件,就會在物件數量達到最大堆容量限制後產生記憶體溢位異常。

出現這種異常,一般手段是先通過記憶體映像分析工具(如Eclipse Memory Analyzer)對dump出來的堆轉存快照進行分析,重點是確認記憶體中的物件是否是必要的,先分清是因為記憶體洩漏(Memory Leak)還是記憶體溢位(Memory Overflow)。

如果是記憶體洩漏,可進一步通過工具檢視洩漏物件到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的應用中,要特別注意這點。

相關推薦

異常記憶體溢位OOM情況

1、堆記憶體溢位 【情況一】:   java.lang.OutOfMemoryError: Java heap space:這種是java堆記憶體不夠,一個原因是真不夠,另一個原因是程式中有死迴圈;   如果是java堆記憶體不夠的話,可以通過調整J

Linux下jenkins改埠解決記憶體溢位版本升級

1、新版本的jenkins修改埠 新版本jenkins的配置檔案在/etc/sysconfig/jenkins vi /etc/sysconfig/jenkins 找到JENKINS_PORT="80

關於記憶體溢位遇到的兩情況

1.處理資料的程式或者服務是x86架構的,容易出現記憶體溢位。 因為x86的程序,最多允許記憶體4g、在這4g中又有2g是作業系統等、所以當你查詢的資料量非常大的時候,非常容易記憶體溢位。 2.多執行緒 容易導致記憶體溢位(溢位原理細節我還不清楚) 我查詢mongo資料量,資料按地區分類,我查到A地區有

寫程式碼實現棧溢位溢位永久代溢位直接記憶體溢位

棧溢位(StackOverflowError) 堆溢位(OutOfMemoryError:Java heap space) 永久代溢位(OutOfMemoryError: PermGen space) 直接記憶體溢位 一、堆溢位 建立物件時如果沒有可以分配的堆記憶體,

學習筆記 --- JVM 溢位溢位永久代溢位直接記憶體溢位

棧溢位(StackOverflowError)           ---    遞迴引起  棧空間不足      ---   執行緒請求的棧

Spark Heap OOM(記憶體溢位)

spark任務在除錯過程中,OOM是非常討厭的一種情況。本文針對Heap OOM的情況先做一定分析,告訴大家如何調參。 1.Heap OOM的現象 如果在Spark UI或者在spark.log中看到如下日誌: java.lang.OutOfMemoryError: G

優雅地使用Handler,避免記憶體溢位空指標

在Activity中直接建立Handler的內部類,比如這樣: public class HandlerActivity extends AppCompatActivity { private Handler mHandler = new Handler() {

JVM 記憶體溢位追蹤調優與 記憶體溢位溢位原因

出處1:http://www.iteye.com寫java程式時大家一定對一下兩條異常並不陌生: java.lang.OutOfMemoryError: Java heap space java.lang.OutOfMemoryError: PermGen space 尤其當

記憶體區別

Java把記憶體分成兩種,一種叫做棧記憶體,一種叫做堆記憶體。 在函式中定義的一些基本型別的變數和物件的引用變數都是在函式的棧記憶體中分配。當在一段程式碼塊中定義一個變數時,java就在棧中為這個變數分配記憶體空間,當超過變數的作用域後,java會自動釋放,該記憶體空間可以

Java中棧記憶體記憶體方法區——淺析

  java中記憶體分配策略及堆和棧的比較  1 記憶體分配策略   按照編譯原理的觀點,程式執行時的記憶體分配有三種策略,分別是靜態的,棧式的,和堆式的. 靜態儲存分配是指在編譯時就能確定每個資料目標在執行時刻的儲存空間需求,因而在編譯時就可以給他們分配固定的記憶體空間.這種分配策略要求程式程式碼中不允許有

Java中編譯期執行期記憶體和棧記憶體詳解

java中記憶體分配策略及堆和棧的比較    1 記憶體分配策略    按照編譯原理的觀點,程式執行時的記憶體分配有三種策略,分別是靜態的,棧式的,和堆式的.    靜態儲存分配是指在編譯時就能確定每個資料目標在執行時刻的儲存空間需求,因而在編譯時就可以給他們分配固定的記憶體空間.這種分配策略要求程式程式碼中

iOS開發時OC與C的混編中,strcpy導致的記憶體溢位野指標

在最近的專案開發中,由於需要使用C語言的演算法供給OC專案呼叫,所以研究了一下OC與C的混編及.a庫的相關生成。而在混編的過程中,C語言的演算法都能正常呼叫了,但是被一個問題困擾了很長一段時間,就是在

Android之記憶體洩露記憶體溢位記憶體抖動分析

記憶體 JAVA是在JVM所虛擬出的記憶體環境中執行的,記憶體分為三個區:堆、棧和方法區。 棧(stack):是簡單的資料結構,程式執行時系統自動分配,使用完畢後自動釋放。優點:速度快。 堆(heap):用於存放由new建立的物件和陣列。在堆中分配的記憶體,一方面由jav

解釋:記憶體溢位記憶體洩露記憶體越界緩衝區溢位溢位

記憶體溢位就是你要求分配的記憶體超出了系統能給你的,系統不能滿足 需求,於是產生溢位。 ================================================================ 記憶體洩漏是指你向系統申請分配記憶體進行使用

solrsolrcloud記憶體溢位記憶體不釋放問題解決方法

本人在使用solrcloud的時候發現記憶體有時候都快80-90%多了還不釋放,可能再過一段時間就oom了,從而整個叢集不能對外提供服務了,該問題一直困惑著我,後來我寫一個一個小工具可以對solr任意版

面試題9:數組的插入的刪除排序

art 面試 rewind 刪除 test from minimum 面試題 排序 參考:白話經典算法系列之七 堆與堆排序 1 #include <iostream> 2 #include <climits> 3 #include <v

JVM之記憶體溢位情況以及可以採取的解決方案

開發中遇到過以下三種記憶體溢位的狀況: 一、 java.lang.OutOfMemoryError: Java heap space 二、 java.lang.OutOfMemoryError: PermGen space 三、 java.lang.OutO

演算法導論 第六章:排序 筆記(維護的性質排序演算法優先順序佇列排序的程式碼實現)

堆排序(heapsort) 像合併排序而不像插入順序,堆排序的執行時間為O(nlgn) 。像插入排序而不像合併排序,它是一種原地( in place) 排序演算法:在任何時候,陣列中只有常數個元素儲存在輸入陣列以外。 堆: (二叉)堆資料結構是一種陣列物件,它可以被視為一棵完全二叉樹。樹

記憶體溢位OOM

什麼是OOM?      OOM是out of memory的簡稱,也稱記憶體溢位。       什麼樣的場景下會出現OOM?        1、在對圖片進行記憶體快取處理的時候就

jvm記憶體溢位後,其他執行緒是否可繼續工作

    最近網上出現一個美團面試題:“一個執行緒OOM後,其他執行緒還能執行嗎?”。我看網上出現了很多不靠譜的答案。這道題其實很有難度,涉及的知識點有jvm記憶體分配、作用域、gc等,不是簡單的是與否的問題。     由於題目中給出的OOM,java中