JVM內存管理機制

堆(Heap)和非堆(Non-heap)內存 按照官方的說法:“Java 虛擬機具有一個堆,堆是運行時數據區域,所有類實例和數組的內 存均從此處分配。堆是在 Java 虛擬機啓動時創建的。”“在 JVM 中堆之外的內存稱爲非堆 內存(Non-heap memory)”。可以看出 JVM 主要管理兩種類型的內存:堆和非堆。簡單來說 堆就是 Java 代碼可及的內存,是留給開發人員使用的;非堆就是 JVM 留給 自己用的,所 以方法區、JVM 內部處理或優化所需的內存(如 JIT 編譯後的代碼緩存)、每個類結構(如運 行時常數池、字段和方法數據)以及方法和構造方法 的代碼都在非堆內存中。 堆內存分配 JVM 初始分配的內存由-Xms 指定, 默認是物理內存的 1/64; JVM 最大分配的內存由 -Xmx 指定,默認是物理內存的 1/4。默認空餘堆內存小於 40%時,JVM 就會增大堆直到-Xmx 的 最大限制;空餘堆內存大於 70%時,JVM 會減少堆 直到-Xms 的最小限制。因此服務器一 般設置-Xms、-Xmx 相等以避免在每次 GC 後調整堆的大小。 非堆內存分配 JVM 使 用 -XX:PermSize 設 置 非 堆 內 存 初 始 值 , 默 認 是 物 理 內 存 的 1/64 ; 由 XX:MaxPermSize 設置最大非堆內存的大小,默認是物理內存的 1/4。 JVM 內存限制(最大值) 首先 JVM 內存限制於實際的最大物理內存(廢話!呵呵),假設物理內存無限 大的話,JVM 內存的最大值跟操作系統有很大的關係。 簡單的說就 32 位處理器雖然可控內存空間有 4GB, 但是具體的操作系統會給一個限制,這個限制一般是 2GB-3GB(一般來說 Windows 系統 下爲 1.5G-2G,Linux 系統下爲 2G-3G) ,而 64bit 以上的處理器就不會有限制了。 衆所周知,jvm 的內存是受限的,一爲機器的體系架構,二爲操作系統本身。 x86,x86-64,SPARC,.....的內存映射是不同,而各操作系統的內存管理機制也有區別。 1. Heap 設定與垃圾回收 Java Heap 分爲 3 個區,Young,Old 和 Permanent。Young 保 存剛實例化的對象。當該區被填滿時,GC 會將對象移到 Old 區。Permanent 區則負責保存 反射對象,本文不討論該區。JVM 的 Heap 分配可以使用-X 參數設定, -Xms -Xmx -Xmn 初始 Heap 大小 java heap 最大值 young generation 的 heap 大小 JVM 有 2 個 GC 線程。第一個線程負責回收 Heap 的 Young 區。第二個線程在 Heap 不足 時,遍歷 Heap,將 Young 區升級爲 Older 區。Older 區的大小等於-Xmx 減去-Xmn,不能 將-Xms 的值設的過大,因爲第二個線程被迫運行會降低 JVM 的性能。 爲什麼一些程序頻繁發生 GC?有如下原因: l l l l 程序內調用了 System.gc()或 Runtime.gc()。 一些中間件軟件調用自己的 GC 方法,此時需要設置參數禁止這些 GC。 Java 的 Heap 太小,一般默認的 Heap 值都很小。 頻繁實例化對象,Release 對象。此時儘量保存並重用對象,例如使用 StringBuffer() 和 String()。 如果你發現每次 GC 後,Heap 的剩餘空間會是總空間的 50%,這表示你的 Heap 處 於健康狀態。 許多 Server 端的 Java 程序每次 GC 後最好能有 65%的剩餘空間。 經驗之談: 1.Server 端 JVM 最好將-Xms 和-Xmx 設爲相同值。爲了優化 GC,最好讓-Xmn 值約等於 -Xmx 的 1/3[2]。 2.一個 GUI 程序最好是每 10 到 20 秒間運行一次 GC,每次在半秒之內完成[2]。 注意: 1.增加 Heap 的大小雖然會降低 GC 的頻率,但也增加了每次 GC 的時間。並且 GC 運行 時,所有的用戶線程將暫停,也就是 GC 期間,Java 應用程序不做任何工作。 2.Heap 大小並不決定進程的內存使用量。進程的內存使用量要大於-Xmx 定義的值,因爲 Java 爲其他任務分配內存,例如每個線程的 Stack 等。 2.Stack 的設定 每個線程都有他自己的 Stack。 -Xss 每個線程的 Stack 大小 Stack 的大小限制着線程的數量。如果 Stack 過大就好導致內存溢漏。-Xss 參數決定 Stack 大小,例如-Xss1024K。如果 Stack 太小,也會導致 Stack 溢漏。 3.硬件環境 硬件環境也影響 GC 的效率,例如機器的種類,內存,swap 空間,和 CPU 的數量。 如果你的程序需要頻繁創建很多 transient 對象,會導致 JVM 頻繁 GC。這種情況你可以增 加機器的內存,來減少 Swap 空間的使用[2]。 4.4 種 GC 第一種爲單線程 GC,也是默認的 GC。,該 GC 適用於單 CPU 機器。 第二種爲 Throughput GC,是多線程的 GC,適用於多 CPU,使用大量線程的程序。第二 種 GC 與第一種 GC 相似,不同在於 GC 在收集 Young 區是多線程的,但在 Old 區和第一 種一樣,仍然採用單線程。-XX:+UseParallelGC 參數啓動該 GC。 第三種爲 Concurrent Low Pause GC,類似於第一種,適用於多 CPU,並要求縮短因 GC 造成程序停滯的時間。這種 GC 可以在 Old 區的回收同時,運行應用程序。 -XX:+UseConcMarkSweepGC 參數啓動該 GC。 第四種爲 Incremental Low Pause GC,適用於要求縮短因 GC 造成程序停滯的時間。這種 GC 可以在 Young 區回收的同時,回收一部分 Old 區對象。-Xincgc 參數啓動該 GC。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章