標籤:
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.lang.OutOfMemoryError: Requested array size exceeds VM limit
[java] view plaincopy
- Java.lang.OutOfMemoryError: Requested array size exceeds VM limit
該例外表明有一數組請求一個超過VM預先分配的記憶體大小的記憶體值。 如果我們遇到該類異常我們該怎麼辦?我們需要檢出源碼,以確保確實沒有動態或靜態建立如此之大的數組。 不過還好,最後版本的VM一般不會有這樣的限制。
Java代碼
- Java.lang.OutOfMemoryError : PermGen space
[java] view plaincopy
- Java.lang.OutOfMemoryError : PermGen space
當Java Heap 中的Perm 記憶體區滿的時候,JVM會拋出上面的一樣的異常。
在一些Java虛擬機器中, 如Sun 公司的HotSpot Java虛擬機器, 一Block Storage類對象或方法對象的專有記憶體稱為永久一代(又稱永久地區)。我們可以想象一下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代碼
- JVMDUMP013I Processed dump event “systhrow”, detail “java/lang/OutOfMemoryError”.
[java] view plaincopy
- 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相關的,呵:
Java代碼
- JVMDG274: Dump Handler has Processed OutOfMemory.
- Exception in thread "main" java.lang.OutOfMemoryError
- at HeapExhaustionSimulator.main(HeapExhaustionSimulator.java:20)
[java] view plaincopy
- JVMDG274: Dump Handler has Processed OutOfMemory.
- Exception in thread "main" java.lang.OutOfMemoryError
- at HeapExhaustionSimulator.main(HeapExhaustionSimulator.java:20)
以下異常,似乎仍然沒啥線索能夠說明是本地記憶體還是Java heap中拋出。不過”sun.misc.Unsafe.allocatedMemory(Native Method)”表明似乎是本地記憶體相關的。
Java代碼
- Exception in thread "main" java.lang.OutOfMemoryError
- at sun.misc.Unsafe.allocateMemory(Native Method)
- at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:99)
- at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)
- at NativeMemorySimulator.main(NativeMemorySimulator.java:11)
[java] view plaincopy
- Exception in thread "main" java.lang.OutOfMemoryError
- at sun.misc.Unsafe.allocateMemory(Native Method)
- at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:99)
- at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)
- at NativeMemorySimulator.main(NativeMemorySimulator.java:11)
以下異常, JAVA 虛擬機器指定Java Heap 中拋出java.lang.OutOfMemoryError.
Java代碼
- java.lang.OutOfMemoryError: Java heap space
- Dumping heap to java_pid6280.hprof ...
- Heap dump file created [50549348 bytes in 1.444 secs]
[java] view plaincopy
- java.lang.OutOfMemoryError: Java heap space
- Dumping heap to java_pid6280.hprof ...
- Heap dump file created [50549348 bytes in 1.444 secs]
你以往可能見過像這樣的一個異常:
Java代碼
- java.lang.OutOfMemoryError: requested NNN bytes for MMMM. Out of swap space?
[java] view plaincopy
- java.lang.OutOfMemoryError: requested NNN bytes for MMMM. Out of swap space?
從字面上, 您可能會檢查作業系統的swap 的配置大小,不過JVM似乎也不確定swap space 是不是最主要的原因。我們可以檢查一下JVM是否已經使用了大量的本地記憶體, 我們還需確定有足夠的記憶體提供給JVM,以及沒有其他進程正在耗盡大量的記憶體資源。最後我們有必要嘗試找一些MMMM相關的bug。
Java代碼
- Java.lang.OutOfMemoryError: unable to create native thread
[java] view plaincopy
- 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 將會在作業系統的臨時目錄下產生。 關於作業系統的預設臨時目錄位置和配置資訊,請參閱你的作業系統手冊。
Java.lang.OutOfMemoryError是什麼