1. 程式人生 > >Java堆記憶體的10個要點

Java堆記憶體的10個要點

導讀:對於程式設計師來說,知道堆空間,設定堆空間,處理堆空間的outOfMemoryError錯誤,分析heap dump是非常重要的。文中介紹了Java堆的學習教程以及Java堆記憶體(heap memory)的十個要點。

文章內容如下:

我剛開始學習Java程式設計時,可不知道什麼是堆記憶體或堆空間(heap space),甚至根本不管物件建立時都放在哪裡去了。正式了寫一些程式後,經常會遇到java.lang.outOfMemoryError等錯誤,我才開始關注堆記憶體。

對大多數程式設計師都經歷過這樣的過程,因為學習一種語言是非常容易來的,但是學習基礎是非常難的,因為沒有什麼特定的流程讓你學習程式設計的每個基礎,使你發覺程式設計的祕訣。

對於程式設計師來說,知道堆空間,設定堆空間,處理堆空間的outOfMemoryError錯誤,分析heap dump是非常重要的。這個關於Java堆的教程是給我剛開始學程式設計的兄弟看的。如果你知道這個基礎知識或者知道底層發生了什麼,當然可能幫助不是那麼大。除非你知道了物件被建立在堆中,否則你不會意識到OutOfMemoryError是發生在堆空間中的。我儘可能的將我所知道的所有關於堆的知識都寫下來了,也希望你們能夠儘可能多的貢獻和分享你的知識,以便可以讓其他人也受益。

Java中的堆空間是什麼?

當Java程式開始執行時,JVM會從作業系統獲取一些記憶體。JVM使用這些記憶體,這些記憶體的一部分就是堆記憶體。堆記憶體通常在儲存地址的底層,向上排列。當一個物件通過new關鍵字或通過其他方式建立後,物件從堆中獲得記憶體。當物件不再使用了,被當做垃圾回收掉後,這些記憶體又重新回到堆記憶體中。要學習垃圾回收,請閱讀”Java中垃圾回收的工作原理”。

如何增加Java堆空間

在大多數32位機、Sun的JVM上,Java的堆空間預設的大小為128MB,但也有例外,例如在32未Solaris作業系統(SPARC平臺版本)上,預設的最大堆空間和起始堆空間大小為 -Xms=3670K 和 -Xmx=64M。對於64位作業系統,一般堆空間大小增加約30%。但你使用Java 1.5的throughput垃圾回收器,預設最大的堆大小為實體記憶體的四分之一,而起始堆大小為實體記憶體的十六分之一。要想知道預設的堆大小的方法,可以用預設的設定引數開啟一個程式,使用JConsole(JDK 1.5之後都支援)來檢視,在VM Summary頁面可以看到最大的堆大小。

用這種方法你可以根據你的程式的需要來改變堆記憶體大小,我強烈建議採用這種方法而不是預設值。如果你的程式很大,有很多物件需要被建立的話,你可以用-Xms and -Xmx這兩個引數來改變堆記憶體的大小。Xms表示起始的堆記憶體大小,Xmx表示最大的堆記憶體的大小。另外有一個引數 -Xmn,它表示new generation(後面會提到)的大小。有一件事你需要注意,你不能任意改變堆記憶體的大小,你只能在啟動JVM時設定它。

堆和垃圾回收

我們知道物件建立在堆記憶體中,垃圾回收這樣一個程序,它將已死物件清除出堆空間,並將這些記憶體再還給堆。為了給垃圾回收器使用,堆主要分成三個區域,分別叫作New Generation,Old Generation或叫Tenured Generation,以及Perm space。New Generation是用來存放新建的物件的空間,在物件新建的時候被使用。如果長時間還使用的話,它們會被垃圾回收器移動到Old Generation(或叫Tenured Generation)。Perm space是JVM存放Meta資料的地方,例如類,方法,字串池和類級別的詳細資訊。你可以檢視“Java中垃圾回收的工作原理”來獲得更多關於堆和垃圾回收的資訊。

java

Java堆中的OutOfMemoryError錯誤

當JVM啟動時,使用了-Xms 引數設定的對記憶體。當程式繼續進行,建立更多物件,JVM開始擴大堆記憶體以容納更多物件。JVM也會使用垃圾回收器來回收記憶體。當快達到-Xmx設定的最大堆記憶體時,如果沒有更多的記憶體可被分配給新物件的話,JVM就會丟擲java.lang.outofmemoryerror,你的程式就會當掉。在丟擲 OutOfMemoryError之前,JVM會嘗試著用垃圾回收器來釋放足夠的空間,但是發現仍舊沒有足夠的空間時,就會丟擲這個錯誤。為了解決這個問題,你需要清楚你的程式物件的資訊,例如,你建立了哪些物件,哪些物件佔用了多少空間等等。你可以使用profiler或者堆分析器來處理 OutOfMemoryError錯誤。”java.lang.OutOfMemoryError: Java heap space”表示堆沒有足夠的空間了,不能繼續擴大了。”java.lang.OutOfMemoryError: PermGen space”表示permanent generation已經裝滿了,你的程式不能再裝在類或者再分配一個字串了。

Java Heap dump

Heap dump是在某一時間對Java堆記憶體的快照。它對於分析堆記憶體或處理記憶體洩露和Java.lang.outofmemoryerror錯誤是非常有用的。在JDK中有一些工具可以幫你獲取heap dump,也有一些堆分析工具來幫你分析heap dump。你可以用“jmap”來獲取heap dump,它幫你建立heap dump檔案,然後,你可以用“jhat”(堆分析工具)來分析這些heap dump。

Java堆記憶體(heap memory)的十個要點:

1. Java堆記憶體是作業系統分配給JVM的記憶體的一部分。

2. 當我們建立物件時,它們儲存在Java堆記憶體中。

3. 為了便於垃圾回收,Java堆空間分成三個區域,分別叫作New Generation, Old Generation或叫作Tenured Generation,還有Perm Space。

4. 你可以通過用JVM的命令列選項 -Xms, -Xmx, -Xmn來調整Java堆空間的大小。不要忘了在大小後面加上”M”或者”G”來表示單位。舉個例子,你可以用 -Xmx256m來設定堆記憶體最大的大小為256MB。

5. 你可以用JConsole或者 Runtime.maxMemory(), Runtime.totalMemory(), Runtime.freeMemory()來檢視Java中堆記憶體的大小。

6. 你可以使用命令“jmap”來獲得heap dump,用“jhat”來分析heap dump。

7. Java堆空間不同於棧空間,棧空間是用來儲存呼叫棧和區域性變數的。

8. Java垃圾回收器是用來將死掉的物件(不再使用的物件)所佔用的記憶體回收回來,再釋放到Java堆空間中。

9. 當你遇到java.lang.outOfMemoryError時,不要緊張,有時候僅僅增加堆空間就可以了,但如果經常出現的話,就要看看Java程式中是不是存在記憶體洩露了。

10. 請使用Profiler和Heap dump分析工具來檢視Java堆空間,可以檢視給每個物件分配了多少記憶體。