這篇文章主要介紹了JVM中垃圾回收機制的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
分為三個部分(以下名詞表示同一個區):
新生區、新生代、年輕代
養老區、老年區、老年代
永久區、永久代

唯一目的就是優化GC性能。
如果沒有分代,我們所有的對象都放在一塊,GC的時候我們需要對堆的所有區域進行掃描。而很多的對象都是“朝生夕死”的,如果把創建的新的對象都放在某一地方,當GC的時候就先把“朝生夕死”對象的區域進行回收,這樣就會騰出很多大的空間來。
新生區分為:Eden區、Survivor0區、Survivor1區(也稱為from區和to區)
其中Eden區占80%的內存空間,每塊Survivor各占用10%的內存空間(如:Eden占800M,每個Survivor占100M)
1.開始時創建的對象都是分配在Eden區域中,當Eden區快滿了,就會觸發垃圾回收Minor GC(使用復制算法進行垃圾回收)

2.Minor GC處理后,首先會把Eden區中還存活著的對象一次性轉入其中一塊空閑著的Survivor區。然后清空Eden區,之后創建的對象就繼續放入Eden區中了,直至下次Eden又被填滿。

3.Eden再次被填滿時,就會再次出發Minor GC,清理后(Minor會清理Eden區和Survivor區的內存),Eden區和存在對象的Survivor區(此時的from區)中存活的對象轉移到另一塊空著的Survivor區中(此時的to區),并清空Eden區和之前存在對象的Survivor區(此時變為to區了,“From”和“To”會交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。)
這就是復制算法的流程。
一直要保持一個Survivor區是空的以提供復制算法垃圾回收,而這塊區域的內存只占整塊的10%,其他90%內存都可以被使用,課件內存利用率還是相當高的。
默認情況下,如果新生區中的某個對象經歷了15次GC后,還是沒有被回收掉,那么它就會被轉入老年區。
可通過JVM參數“-XX:MaxTenuringThreshold”來設置,默認是15。
這種方法不用等到經歷GC15次。
假如一批對象總大小大于當前Survivor區內存的50%,那么大于等于這批對象年齡的對象就會被轉移到老年區。
例:假設Survivor0區中的兩個對象都經歷的3次GC(年齡3),而且這兩個對象總大小50M,超過了Survivor0區內存大小的一半。那么此時Survivor0區中年齡大于等于3歲的對象就都要被全部轉移到老年區。

有一個JVM參數"-XX:PretenureSizeThreshold",默認值是0,表示任何情況都先把對象分配給Eden區。
若設置為1048576字節,也就是1M。則表示當創建的對象大于1M時,就會直接把這個對象放入到老年區,就根本不會經過新生區了。
這么做的原因:大對象在經歷復制算法進行GC的時候會降低性能。
Minor GC后存活的對象太多,導致Survivor區放不下了,此時就會將所有的對象直接轉移到老年區中。
執行每一次Minor GC前,JVM都先檢查一下老年區可用的內存空間是否大于新生區所有對象的總大小。
原因:極端情況下,Minor GC后,新生代中所有的對象都活了下來,那就會把所有新生代中的對象放入老年區中。
如果說老年區可用內存大于新生代對象總大小,那么就可以放心的執行Minor GC。
但如果老年區內存小于新生區對象的總大小,這時候就會看一個參數:“-XX:HandlePromotionFailure”是否設置為true了。如果為true,就進入下一次判斷,看老年區可用內存是否大于之前每次Minor GC后進入老年區對象的平均大小。如果老年代可用內存小于平均大小或是參數沒有設置成true,那就會直接觸發“Full GC”,就是對老年代進行垃圾回收,騰出空間后,再進行Minor GC,相當于對新生區、老年區統一做了一次清理。
三種情況遞進理解:
1.如果Minor GC后,存活的對象<Survivor區大小,直接進入Survivor區即可;
2.如果Minor GC后,存活的對象>Survivor區大小,但<老年區可用內存,直接進入老年區;
3.若Minor GC后,此時老年區都放不下這些存活的對象了,就會觸發Full GC;
如果Full GC后老年區內存還是不夠用,就會導致OOM內存溢出。
標記整理算法
【原理】
一開始對象都是任意分布的,在經歷完垃圾回收之后,就會標記出哪些是存活對象,哪些是垃圾對象,然后就會把這些存活的對象在內存中進行整理移動,盡量都挪到一邊去靠在一起,然后再把垃圾對象進行清除,這樣做的好處就是避免了垃圾回收后產生的大片內存碎片。

【缺點】
較為耗時,比復制算法慢10倍;
所以如果系統頻繁出現Full GC,會嚴重影響系統性能,出現卡頓。所以JVM優化的一大問題就是減少Full GC頻率。
新生區和老年區進行垃圾回收時是通過不同的垃圾回收器進行回收的
Seral 和 Seral Old垃圾回收器
分別用于回收新生區和老年區。
單線程運行,垃圾回收時會停止我們系統的其他線程,再執行垃圾回收(不再使用);
ParNew和CMS垃圾回收器
分別用于新生區和老年區;
多線程并發,性能更好,現在一般是線上生產系統的標配。
G1垃圾回收器
統一收集新生區和老年區,采用更加優秀的算法機制。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“JVM中垃圾回收機制的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。