search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

Java虛擬機總結1---垃圾回收機制

導語

作為java工程師,對於java虛擬機內部機制不能不了解一些,這樣才在分析疑難問題時有的放矢。

前段時間定了個小目標,利用晚上的時間拜讀大名鼎鼎的周志明的《深入理解Java虛擬機》,才看幾章,「人民的名義」火起來了。唉,時間被強行奪了去,小目標眼睜睜的被失敗了。

所以在這裡強行立flag吧,先把這幾章的心得總結在這裡,解解達康書記的毒。

現在的主流虛擬機一般都採用分代回收,新生代、老年代。

一、分代

1.為什麼要分代?有什麼意義?這裡我們假設沒有分代,會怎麼樣呢?

答:「stop the world」,程序被卡成翔。

為什麼 ? 因為gc的時候需要分析死亡對象,所以不允許這個時候對象引用關係再發生變化,這就要求「stop the world」,所以線程必然會被掛起。所以我們為了盡量讓用戶無感知,必然要提高gc效率。怎麼提高,答案就是分代。我們把長活對象放在一塊稱為老年代,再把短命鬼放在另一塊稱為新生代。這樣我們一般情況下只需要掃描新生代區域回收無用對象即可減少world被stoped的時間,讓用戶在gc時依然有絲滑般的順暢感。

2.分代實現

我們可以看到新生代內存分配要比老年代更複雜一些,為什麼會有這個區別呢?

答:垃圾清理演算法的不同。

新生代:複製演算法;老年代:標記-整理演算法。

複製演算法:

上圖可以明顯看到,它將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活著的對象複製到另外一塊上面,然後再把已使用過的內存空間一次清理掉。它的優點就是不用考慮內存碎片等複雜情況,只要移動堆頂指針,按順序分配內存即可,實現簡單,運行高效。但有個致命缺點就是要「浪費「一半的內存,這太蛋疼了。

那可不可以少浪費一點呢?

答:可以的,就是Survivor區 ,它與eden區比例是1:8,有兩個survivor區,其中一個survivor區和eden區是可用的,另一個survivor區是gc複製區,這樣被浪費的區域只有1/10了,大大減少了。但是這樣真的合理嗎,可以滿足實際需要嗎,當然是可以的,IBM公司研究過,98%的Java對象都是」朝生夕死「,生命期很短的,這樣每次gc之後大部分對象都over了,真正存活下來的是少數,所以我們只用1/10的空間存在這些存活對象就夠了。但是,異常情況也是有的,萬一存活對象所佔內存多於survivor區怎麼辦呢,當然也是有解決方案:分配擔保。就是內存不足的時候由擔保方承擔,這個擔保方就是老年代區。所以這裡可以看到老年代扮演著最後的大佬的角色,同時可以看到這種演算法的致命缺點就是必須要有一個擔保方。所以老年代不能採用這種方式,因為他就是最後的擔保方,沒有人再能給它擔保,除非survivor區佔一半內存,但是這又太浪費了。最後,老年代使用了」標記-整理「演算法。

標記-整理演算法:

分為兩個階段,首先標記所有存活對象,接著讓所有存活的對象都向一端移動,然後直接清理掉端邊界以外的內存,這樣就完全的利用了所有內存了。

到這裡可能會有人疑問,新生代為什麼不也採用這種演算法,不就也能充分利用所有的內存了嗎?其實這裡是兩種演算法出發點的不同,所謂複製演算法是空間換時間,而標記-整理演算法則是時間換空間。

複製演算法在工作的時候是不沒有獨立的「mark」與「copy」階段的,而是合在一起做一個動作,就叫複製。也就是說,每發現一個這次收集中尚未訪問過的活對象就直接copy到新地方,同時設置forwarding pointer。 這樣的工作方式就需要多一份空間。

標記-整理演算法在工作的時候則需要分別的mark與整理階段,mark階段用來發現並標記所有活的對象,然後整理階段才移動對象來達到整理內存的目的。在mark之後就可以按順序一個個對象「滑動」到空間的某一側。因為已經先遍歷了整個空間里的對象圖,知道所有的活對象了,所以移動的時候就可以在同一個空間內而不需要多一份空間。

總結一下就是:新生代存活對象少,為了快速gc我們可以浪費一點內存;而老年代存活對象多,我們更在乎內存,同時因為有效對象多,所以這塊區域的gc應該比新生代少。這就是我們下面要講的minor gc和full gc。

二、普通GC(minor GC):全局GC

從上面我們知道新生代的gc是快速而頻繁的,老年代gc是緩慢而稀少的。這也是分代的目的所在,大部分「朝生夕死」的對象可以快速被清理掉,而長存對象被放在特權區,在平常的minor gc的時候是不會被掃描到的,這樣就大大的提高了gc的命中率了。

那到底什麼時候full gc會被觸發呢,當然也是老年代內存不足的時候。所以這裡再說一下什麼情況下,對象會被放到老年代:

i. 對象足夠老,所謂足夠老就是經過多次gc之後依然存活的對象,這裡的預設設置是15次。

ii.分配擔保中標的對象,就是上面說的minor gc的時候當新生代survivor區不足以存放的存活對象。

iii. 大對象,我們知道堆內存並不是連續的,有可能在一段時間之後內存很碎片化了,這樣即使剩餘總內存依然足夠,但是在eden space已經找不到一塊連續區域存放這個大對象了,這時候我們就知道把大對象直接放在老年代了。這樣的情況如果發生多次我們可以想象,老年很快就會被佔滿,導致full gc的發生,而full gc就比minor gc慢很多(大概10倍),world就真被stop了。所以我們盡量必須new 大對象尤其是很多大對象一起new。

溫馨提醒:

1、微信端搜索課程

在「騰訊課堂」官方微信里,回復你想學習的內容,即可快速找到你期待的課程哦!

2、學習方式

【電腦端】

*可通過登錄ke.qq.com進入學習;

*可通過windows PC版QQ客戶端面板上的課堂入口進入學習。

【移動端】

*下載APP 「騰訊課堂」 即可進入學習;

*關注微信公眾號或者手Q公眾號「騰訊課堂」,進入學習。

(註:微信和QQ的課程報名信息獨立,登錄時請選擇對應的登錄方式)



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦