Java堆內存的10個要點
當我開始學習 Java 編程時,我不知道什么是堆內存或堆空間,我甚至不知道當對象創建時,它們被放在了哪里。當我開始正式寫一些程序后,我會經常遇到 java.lang.outOfMemoryError 的報錯,之后我才開始關注什么是堆內存或者說堆空間(heap space)。對大多數程序員都經歷過這樣的過程,因為學習一種語言是非常容易來的,但是學習基礎是非常難的,因為沒有什么特定的流程讓你學習編程的每個基礎,使你發覺編程的秘訣。對于程序員來說,知道堆空間,設置堆空間,處理堆空間的 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 堆中的 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 堆空間,可以查看給每個對象分配了多少內存。
原文鏈接:java revisited 編譯:伯樂在線 - 唐小娟