瞭解JVM的內存管理與垃圾回收

瞭解JVM的內存管理與垃圾回收

2007-03-07

版權聲明:轉載時請以超鏈接形式標明文章原始出處和作者信息及本聲明
http://aleung.blogbus.com/logs/4712392.html

Java語言具備GC(垃圾回收)的能力,內存管理不需要應用程序去過問,這很方便。但是,GC是怎麼進行的,JVM的內存參數應該怎麼調整,如何優化,往往我們不是太清楚。看過一些資料後,對Sun JVM的內存管理以及垃圾回收的機制大概有了一個概念,這裏將這些資料歸納和翻譯出來。本文內容主要基於Sun JVM 1.3.1,在後續版本中有不少優化措施,但是這些基本概念還是不變的。

這裏假設大家對GC的概念和基本原理都已經瞭解,不詳細敘述了。

當JVM進行GC的時候,是要消耗CPU資源和需要一定時間的,這會影響到程序的正常運行,因此需要儘可能減少GC消耗的時間。Java程序運行過程中,對象的生命週期有長有短,其中相當大部分是都是比較短命的,例如局部的對象一用完就可以回收了。在大多數情況下,只要能夠及時回收這些短命對象的內存,就能夠確保JVM有足夠內存來分配給新的對象。因此JVM採用一種分代回收(generational collection) 的策略,用較高的頻率對年輕的對象(young generation)進行掃描和回收,這種叫做minor collection,而對老對象(old generation)的檢查回收頻率要低很多,稱爲major collection。這樣就不需要每次GC都將內存中所有對象都檢查一遍。

Sun JVM 1.3 有兩種最基本的內存收集方式:一種稱爲copying或scavenge,將所有仍然生存的對象搬到另外一塊內存後,整塊內存就可回收。這種方法有效率,但需要有一定的空閒內存,拷貝也有開銷。這種方法用於minor collection。另外一種稱爲mark-compact,將活着的對象標記出來,然後搬遷到一起連成大塊的內存,其他內存就可以回收了。這種方法不需要佔用額外的空間,但速度相對慢一些。這種方法用於major collection.

在JVM 1.3及以後的版本中,還有其他可選的內存收集方法,通過特定的參數來設定。例如:增量式回收,每次只處理一小部分;替代單線程copying的多線程並行回收;替代mark-compact的concurrent mark-sweep回收等等。參考資料[4][5]中有更多描述。

JVM管理的內存,通常叫做堆(heap),可以用下面的圖來描述。

JVM啓動後,保留一段地址空間,這個空間的大小由-Xmx指定。這塊空間的大小就是heap可能的最大值,但一開始不一定全都分配了物理內存,初始分配的heap大小由-Xms指定,如果-Xms小於-Xmx,剩餘部分是virtual的,當需要的時候,再向OS申請。

綠色部分是young generation的內存,由一塊Eden(伊甸園,有意思)和兩塊Survivor Space(1.4文檔中稱爲semi-space)構成。新創建的對象的內存都分配自eden。兩塊Survivor Space總有會一塊是空閒的,用作copying collection的目標空間。Minor collection的過程就是將eden和在用survivor space中的活對象copy到空閒survivor space中。所謂survivor,也就是大部分對象在伊甸園出生後,根本活不過一次GC。對象在young generation裏經歷了一定次數的minor collection後,年紀大了,就會被移到old generation中,稱爲tenuring。(是否僅當survivor space不足的時候纔會將老對象tenuring? 目前資料中沒有找到描述)

淺藍色部分是old generation的內存。

深藍色部分稱爲permanent generation,是JVM用來保存class object和meta data,大小由-XX:PermSize和-XX:MaxPermSize指定。大量動態生成(編譯)和加載class會增加這部分內存的耗用。

剩餘內存空間不足會觸發GC,如eden空間不夠了就要進行minor collection,old generation空間不夠要進行major collection,permanent generation空間不足會引發full GC。

很多參數會影響裏面各部分空間的分配。-XX:MinHeapFreeRatio與-XX:MaxHeapFreeRatio設定空閒內存佔總內存的比例範圍,這兩個參數會影響GC的頻率和單次GC的耗時。-XX:NewRatio決定young與old generation的比例。Young generation空間越大,minor collection頻率越低,但是old generation空間小了,又可能導致major collection頻率增加。-XX:NewSize和-XX:MaxNewSize直接指定了young generation的缺省大小和最大大小。


-Xmx
set maximum Java heap size

-Xms
set initial Java heap size

-XX:MinHeapFreeRatio=40
Minimum percentage of heap free after GC to avoid expansion.

-XX:MaxHeapFreeRatio=70
Maximum percentage of heap free after GC to avoid shrinking.

-XX:NewRatio=2
Ratio of new/old generation sizes. [Sparc -client:8; x86 -server:8; x86 -client:12.]-client:8 (1.3.1+), x86:12]

-XX:NewSize=2.125m
Default size of new generation (in bytes) [5.0 and newer: 64 bit VMs are scaled 30% larger; x86:1m; x86, 5.0 and older: 640k]

-XX:MaxNewSize=
Maximum size of new generation (in bytes). Since 1.4, MaxNewSize is computed as a function of NewRatio.

-XX:SurvivorRatio=25
Ratio of eden/survivor space size [Solaris amd64: 6; Sparc in 1.3.1: 25; other Solaris platforms in 5.0 and earlier: 32]

-XX:PermSize=
Initial size of permanent generation

-XX:MaxPermSize=64m
Size of the Permanent Generation.  [5.0 and newer: 64 bit VMs are scaled 30% larger; 1.4 amd64: 96m; 1.3.1 -client: 32m.]

(上面給出的缺省值不一定準確,不同JVM版本和不同OS環境下會有不同)

這裏給出的只是基本的介紹,下面reference中的文章都很不錯,對進一步瞭解或者查找性能優化參數都有幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章