[JVM-翻譯]揭開java.lang.OutOfMemoryError面紗之一

Java.lang.OutOfMemoryError是什麼 
Java.lang.OutOfMemory是java.lang.VirtualMachineError的一個子類,當Java虛擬機中斷,或是超出可用資源時拋出。很明顯,OutOfMemory是在Java虛擬機資源耗盡的狀況下沒法分配對象時拋出的。不過很不幸,Java的說明文檔並無對該異常進行進一步的闡述。 

Java虛擬機包括六個不一樣的運行時數據區域(內存區域): 
1. 程序計數器(Program Counter Register) 
2. Java虛擬機棧(Java VM Stack) 
3. Java堆(Heap) 
4. 方法區(Java VM Method Area) 
5. 常量池(Runtime Constant Pool) 
6. 本地方法棧(Native Method Stack) 

程序計數器又稱爲PC寄存器,是存放當前正在被執行的Java 字節碼操做指令的地址。 (這裏加些說明: 對於一個運行中的Java 程序而言, 其中的每一個線程都有它本身的PC(程序計數器)寄存器,它是在該線程啓動時建立的。PC寄存器的大小是一個字長,所以它既可以持有一個本地指針,也可以持有一個return Address.) 

Java虛擬機棧是由棧幀(stack frame)組成,幀則是用來存儲線程在執行過程當中的參數,返回值,以及中間結果等。若是在沒有足夠的內存給Java VM棧,或者沒足夠的內存來生成新的線程時,Java虛擬機將拋出OutOfMemoryError。 

Heap是用來存儲Java類實例或數組的。當沒有足夠的內存給新生實例或數組時,Java虛擬機將拋出OutOfMemoryError。 

方法區則是用來存儲類型相關的信息, 如該類型的常量池,字段或方法信息。當方法區沒有足夠內存時也會出現OutOfMemoryError。(這裏加些說明: 類型中的類(靜態)變量一樣也是存儲在方法區中,一個到ClassLoader的引用,一個到Class類的引用) 

運行時常量池包括字段引用以及常量。當常量池沒有足夠內存可用時, 一樣會拋出OutOfMemoryError異常。 

本地方法區是由一些C/C++寫的方法,給予JVM的一些方法支持。 同理,當沒有可用內存時也會拋出OutOfMemoryError異常。 

您可能看到一個與OutOfMemoryError徹底不同的異常:StackOverflowError。 該異常的拋出則是當本地內存棧或者Java虛擬機棧超出配置大小時拋出。 在大多數IBM 的Java虛擬機中,-Xmso命令參數能夠控制操做系統棧線程和本地線程棧大小, -Xss參數能夠控制Javs虛擬機的線程棧大小。 在一些如Sun HotSpot的JVM廠商, Java方法經過C/C++本地指令共享棧幀. –Xss能夠爲一個線程配置最大內存,該值的默認值和平臺,以及具體JVM的實現廠商有關,但通常都在256K-1024K的大小. 請參考你的JVM說明文檔。 在另外文章中咱們會涉及更多關於StackOverflowError的東西。 

如今, 咱們瞭解了哪些內存區域會引發java.lang.OutOfMemory,讓咱們來看看這個實際錯誤信息,該異常像如下哪一種,咱們又該如何去處理它們呢? 

java

Java代碼   收藏代碼
  1. Java.lang.OutOfMemoryError: Requested array size exceeds VM limit   



該例外代表有一數組請求一個超過VM預先分配的內存大小的內存值。 若是咱們遇到該類異常咱們該怎麼辦?咱們須要檢出源碼,以確保確實沒有動態或靜態的建立如此之大的數組。 不過還好,最後版本的VM通常不會有這樣的限制。 

數組

Java代碼   收藏代碼
  1. Java.lang.OutOfMemoryError : PermGen space  



當Java Heap 中的Perm 內存區滿的時候,JVM會拋出上面的同樣的異常。 
在一些Java虛擬機中, 如Sun 公司的HotSpot Java虛擬機, 一塊存儲類對象或方法對象的專有內存稱爲永久一代(又稱永久區域)。咱們能夠想象一下IBM 建模和分析工具的Java GC的perm 區使用方法。 



在圖中,咱們看到」Max Perm」和」Used Tenured」兩按鈕顯示了Perm 區的使用方法和它的最大長度。咱們能夠看到Perm區使用的總內存已經到了它的最大化上限,這就是爲何咱們會獲得 java.lang.OutOfMemoryError: PermGen Space 的異常. 假使沒有內存泄露, 咱們能夠經過調整-XX:MaxPermSize參數選項來增長Perm 區的最大化上限值。 好比這樣: 
-XX:MaxPermSize=128m 

上面選項將設置Perm 區的最大值爲128Mbytes. 

Okay,到如今咱們已經看到因爲耗盡Java Heap或者Java Heap中的Perm區的內存而致使拋出的Java.lang.OutOfMemoryError異常。不過更爲意外的是, 當Java虛擬機在本地內存中, 找不到更多可用內存時, 仍然能夠像在Java Heap中, 拋出Java.langOutOfMemory異常。那麼在這種狀況下, 咱們如何來判定該異常是從Java Heap中仍是本地內存中引起的呢 ? 

在下面的異常中, 沒有啥信息指定該OutOfMemoryError異常是從Java Heap仍是本地內存中拋出: 工具

Java代碼   收藏代碼
  1. JVMDUMP013I Processed dump event 「systhrow」, detail 「java/lang/OutOfMemoryError」.   



如下異常,Java 虛擬機很是友好的告訴咱們足夠的信息說是本地內存耗盡, 在該異常中, JVM描述到 「allocatedMemory failed」,這說明本地內存分配失敗: 
Java.lang.OutOfMemoryError: JVMCI026: allocatedMemory failed 

如下異常,彷佛沒啥線索可以說明是本地內存仍是Java Heap中拋出的異常,不過幸運的是咱們有一個行號,20,還有一個源文件的文件名, HeapExhaustionSimulator.java,好像是和Heap相關的,呵: spa

Java代碼   收藏代碼
  1. JVMDG274: Dump Handler has Processed OutOfMemory.  
  2. Exception in thread "main" java.lang.OutOfMemoryError  
  3. at HeapExhaustionSimulator.main(HeapExhaustionSimulator.java:20)  



如下異常,彷佛仍然沒啥線索可以說明是本地內存仍是Java heap中拋出。不過」sun.misc.Unsafe.allocatedMemory(Native Method)」代表彷佛是本地內存相關的。 操作系統

Java代碼   收藏代碼
  1. Exception in thread "main" java.lang.OutOfMemoryError  
  2. at sun.misc.Unsafe.allocateMemory(Native Method)  
  3. at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:99)  
  4. at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)  
  5. at NativeMemorySimulator.main(NativeMemorySimulator.java:11)  



如下異常, Java 虛擬機指定Java Heap 中拋出java.lang.OutOfMemoryError. 線程

Java代碼   收藏代碼
  1. java.lang.OutOfMemoryError: Java heap space  
  2. Dumping heap to java_pid6280.hprof ...  
  3. Heap dump file created [50549348 bytes in 1.444 secs]  



你以往可能見過像這樣的一個異常: 指針

Java代碼   收藏代碼
  1. java.lang.OutOfMemoryError: requested NNN bytes for MMMM. Out of swap space?  



從字面上, 您可能會檢查操做系統的swap 的配置大小,不過JVM彷佛也不肯定swap space 是否是最主要的緣由。咱們能夠檢查一下JVM是否已經使用了大量的本地內存, 咱們還需肯定有足夠的內存提供給JVM,以及沒有其餘進程正在耗盡大量的內存資源。最後咱們有必要嘗試找一些MMMM相關的bug。 

對象

Java代碼   收藏代碼
  1. Java.lang.OutOfMemoryError: unable to create native thread   


這樣的異常是在說,若是您擁有大量的線程,或者本地內存耗盡時,新的線程企圖建立時拋出。 

Java Heap Dump 是什麼?
 
咱們知道Java Heap 是全部類實例和數組對象分配的一個運行時數據區,其間全部Java VM線程在執行期間共享Heap 中的數據。那麼一個Java heap dump至關於在一個特殊的時間點上生成的一個快照,它就像給一個繁忙的數據倉庫在給定的時間上來了一個照片,咱們經過這張快照能夠識別哪些組件在那快照的那時間點上是可用的。 

因爲Java 說明文檔並無說起到Java heap dump,在各個不一樣的JVM廠商,存在各個對Java heap dump的介紹。 如IBM JVM的Java heap dump 提供的信息大至和Java Heap差很少。 
Sun公司提供的信息基本上是JVM Stack,運行時常量池和Java Heap等. 

如何生成Java Heap Dumps ? 
Java Heap Dumps一般是由JVM自動生成,不過您也能夠強制生成Java Heap Dumps。在大多數IBM的JVM上。Java Heap Dumps 在當Java Heap 用完前自動生成。在大多數Sun 公司的JVM上,你須要在JVM上配置以生成Java Heap dumps. 若是你想在java.lang.OutOfMemory出現時生成,你須要在某些Sun的發行版的JVM配置 –XX:+HeapDumpOnOutOfMemoryError 參數選項. 你一樣須要配置 –agentlib:phrof=heap=dump選項來使用HPROF。若是JVM提供, 你可使用jmap工具, 好比:jmap –dump 1234 將從進程號1234上生成Java heap dump. 你能夠經過調用HotSpotDiagnostic MBean和dumpHeap 來利用JConsole來監視內存。 
若是你想在IBM的JVMs上給JVM崩潰或是用戶信號生成Java heap dumps, 你能夠配置環境變量 IBM_HEAPDUMP和IBM_HEAP_DUMP置爲TRUE. 如:能夠在給IBM JVM發送一個SIGQUIT信號 

具體請參閱你的JVM說明文檔以得到更多信息,由於因爲平臺與廠商的不一樣,選項會有所變化。 

在哪能夠找到Java Heap Dumps ? 
您能夠在JVM進程的當前工做目錄下找到Java heap dumps,除非你指定了另外的目錄位置。 
您能夠在IBM JVMs上經過環境變量指定目錄位置: IBM_HEAPDUMPDIR 和 _CEE_DEPTARG. 
若是沒有足夠的空間給指定的目錄,或JVM在指定目錄下未獲取寫權限, Java Heap dumps 將會在操做系統的臨時目錄下生成。 關於操做系統的默認臨時目錄位置和配置信息,請參閱你的操做系統手冊。 進程

相關文章
相關標籤/搜索