回覆列表
-
1 # 此生唯一
-
2 # 小雨滴516
首先,jvm虛擬機器分為堆,本地方法棧,程式計數器,方法區,虛擬機器棧。其中堆是由
新生代,老年代,永久代組成的。
新生代:Eden區、survivorFrom區、survivorTo區的比例是8:1:1。當有新的物件時,想進入Eden區,如果物件特別大,直接進入老年代。當Eden區記憶體不夠的時候,會觸發一次MinorGC,這次GC掃描了Eden區和survivorFrom區,同時所有的物件年齡都加一。進入survivorTo區。GC過後,survivorTo和survivorFrom互換,survivorFrom變保留了一次GC過後的物件。等待下次GC的時候和Eden區一起被掃描。如果記憶體中的物件一直被呼叫,將不會被清除回收,物件的年齡就會隨著一次次的GC增加,直到增加到15歲,進入老年代,這個15歲是可以設定的。新生代的物件GC採用複製演算法。
老年代:主要放生命週期長的物件。老年代的物件回收是MajorGC,當空間不夠時才會觸發,老年代採用標記-清除演算法。
看到這個問題,我來系統總結下新生代,老年代,永久代的相關內容!
我們都知道JAVA記憶體結構,區分有堆,棧,方法區,本地方法棧,暫存器等一系列結構,而建立的物件都是放在堆中!
我們new一個物件出來,這個物件就是被放入堆中的新生代中進行管理(當然,有些大物件是直接放入老年代的),新生代又分為一個eden和兩個survivor區域,為什麼分呢?因為新生代的物件會更加頻繁的進行物件回收,而新生代中目前採用的回收方法為:複製演算法!
首先保持survivor區中的一塊絕對空閒,eden區和另一個survivor區用來存放物件,在GC的時候,把還不需要清除的物件放入空閒的survivor區,如果有多餘的無需清除的物件,則直接放入老年代,下一此GC的時候,又重新將裝了物件的survivor區和eden區中物件存到空餘的sunvivor區,依次反覆。。
記憶體佔比為:eden區:空閒survivor:物件survivor = 8:1:1
疑問1,為什麼不設定更大的suvivor區,讓每次的多餘物件放入空閒survivor,而是直接放老年代呢?因為新生代的物件基本都是方法內定義的物件,清除比較頻繁,能進入老年代的也不多,所以不需要更大的survivor;
疑問2,為什麼要兩個survivor區倒來倒去?比如在記憶體存放的物件順序為ABC,B優先進行了清除,這個時候A和C之間的記憶體就是空閒的(也成為記憶體碎片),如果在每次GC的時候使用複製演算法,按順序放入suvivor區,就大大減少了記憶體碎片的產生,增加了記憶體使用量;
新生代就說到這,再看老年代(物件存在時間較長) 新生代的物件因為存活時間短,使用複製演算法非常高效,但是老年代中的物件,存活時間較長,如果還是使用複製演算法,則顯得效率太低,所以老年代通常使用標記-整理演算法:
1,標記:在每次GC的時候,將所有繼續存活的物件(還掛在gc roots根上的)標記;
2,整理:移動所有繼續存貨的物件到記憶體一端,完成之後,將邊界外的所有物件進行清除;
最後說下永久代,區別於新生代和老年代,持久代的物件生命週期可理解為跟JVM一樣,存放的是常量,靜態變數等不會釋放的物件,永久代一般設定的記憶體都很少,大約幾M,後期貌似Java取消了永久代,故不做分析。。
更多有關程式設計技術方面的知識,會持續更新,敬請關注。。