標籤:
Sun的JVMGenerationalCollecting(記憶體回收)原理是這樣的:把對象分為年青代(Young)、年老代(Tenured)、持久代(Perm),對不同生命週期的對象使用不同的演算法。(基於對對象生命週期分析)
1.Young(年輕代)
年輕代分三個區。一個Eden區,兩個Survivor區。大部分對象在Eden區中產生。當Eden區滿時,還存活的對象將被複製到Survivor區(兩個中的一個),當這個Survivor區滿時,此區的存活對象將被複製到另外一個Survivor區,當這個Survivor去也滿了的時候,從第一個Survivor區複製過來的並且此時還存活的對象,將被複製年老區(Tenured。需要注意,Survivor的兩個區是對稱的,沒先後關係,所以同一個區中可能同時存在從Eden複製過來對象,和從前一個Survivor複製過來的對象,而複製到年老區的只有從第一個Survivor去過來的對象。而且,Survivor區總有一個是空的。
2.Tenured(年老代)
年老代存放從年輕代存活的對象。一般來說年老代存放的都是生命期較長的對象。
3.Perm(持久代)
用於存放靜態檔案,如今Java類、方法等。持久代對記憶體回收沒有顯著影響,但是有些應用可能動態產生或者調用一些class,例如Hibernate等,在這種時候需要設定一個比較大的持久代空間來存放這些運行過程中新增的類。持久代大小通過-XX:MaxPermSize=進行設定。
舉個例子:當在程式中產生對象時,正常對象會在年輕代中分配空間,如果是過大的對象也可能會直接在年老代產生(據觀測在運行某程式時候每次會產生一個十兆的空間用收發訊息,這部分記憶體就會直接在年老代分配)。年輕代在空間被分配完的時候就會發起記憶體回收,大部分記憶體會被回收,一部分倖存的記憶體會被拷貝至Survivor的from區,經過多次回收以後如果from區記憶體也分配完畢,就會也發生記憶體回收然後將剩餘的對象拷貝至to區。等到to區也滿的時候,就會再次發生記憶體回收然後把倖存的對象拷貝至年老區。
通常我們說的JVM記憶體回收總是在指堆記憶體回收,確實只有堆中的內容是動態申請分配的,所以以上對象的年輕代和年老代都是指的JVM的Heap空間,而持久代則是之前提到的MethodArea,不屬於Heap。
關於JVM記憶體管理的一些建議
1、手動將產生的無用對象,中間對象置為null,加快記憶體回收。
2、對象池技術如果產生的對象是可重用的對象,只是其中的屬性不同時,可以考慮採用對象池來較少對象的產生。如果有閒置對象就從對象池中取出使用,沒有再產生新的對象,大大提高了對象的複用率。
3、JVM調優通過配置JVM的參數來提高記憶體回收的速度,如果在沒有出現記憶體泄露且上面兩種辦法都不能保證JVM記憶體回收時,可以考慮採用JVM調優的方式來解決,不過一定要經過實體機的長期測試,因為不同的參數可能引起不同的效果。如-Xnoclassgc參數等。
Java基礎-JVM記憶體回收