以前咱們學習了 JVM 基本介紹 以及 什麼樣的對象須要被 GC ,今天就來學習一下 JVM 在判斷出一個對象須要被 GC 會採用何種方式進行 GC。在學習 JVM 如何進行垃圾回收方法時,發現所謂的 JVM 垃圾回收思想和現實生活的場景有不少類似的地方。因此本文用餐廳回收餐桌的方式類比 JVM 垃圾回收算法,應該能幫助 JVM 學習的理解和記憶。git
研發園開了家新餐廳,餐廳老闆在考慮如何回收餐盤時首先使用了最簡單的方式,那就是服務員在顧客用餐的過程當中,不定時的觀察餐廳,針對用完餐的顧客記錄他們的位置(固然通常的服務員的腦海中自行處理),統一回收他們的餐具和餐盤。可是這種回收方式會有一個明顯的問題,那就是回收後的餐廳座位,頗有多是不連續的。若是後續有同行的顧客(好比小情侶... ...)想坐在一塊兒,那極可能找不到連續的座位。github
爲了解決餐廳座位碎片化的問題,餐廳的老闆提出了一個大膽的想法,這是一個很會思考的老闆。把餐廳的用餐區域分紅兩部分 A 廳和 B 廳,當對 A 廳中的餐桌作回收時,將 A 廳中還未用完餐的顧客,"請"到 B 廳去用餐,而且讓這些顧客在 B 廳中拼桌用餐(爲了餐位連續)。這樣全部 A 廳中的位置都空餘出來了,而且 B 廳中的用餐區域和未用餐區域都是連續的!簡直是強迫症晚期。看似完美的解決了回收後餐位碎片化的問題。可是依然帶來了其餘的一些問題。算法
缺點:post
餐廳的運營區域是一個總體,如今只能同時對外開放 A 廳,運營空間變小了;學習
當有不少顧客須要從 A 廳轉移到 B 廳時,效率過低;cdn
用餐體驗不好,不被罵娘纔怪。對象
優勢:blog
不容易產生碎片內存
當實行複製算法解決餐位回收後不連續的問題,餐廳的老闆針對新問題又有了新想法,只要移動顧客就能夠解決碎片化問題,爲啥我要將餐廳分紅兩個的部分呢?畢竟那樣不能最大效率的利用餐廳的用餐區域。創造性的提出了標記-整理算法,結合前面兩中方法的優缺點,當餐廳準備回收餐位時,移動全部未用晚餐的顧客,而且讓從餐廳的第一桌開始拼桌。這樣保證後面的餐桌都是已經回收了餐盤的而且回收後的座位都是連續的。這樣既提升了餐廳餐桌的利用率又保證了當有大量組團顧客進店用餐時,餐廳可以提供大量的連續餐桌(這個例子不恰當,若是真的碰到一個要讓人不斷移動造成空位的餐廳,你怕是要開噴了)。文檔
若是仍是用開餐廳的方式來思考 JVM 的話,能夠把分代回收看作餐廳針對不一樣顧客的等級推出的個性化服務。分代收集算法並無新的思想,只是根據對象存活週期的不一樣將內存劃分爲幾塊,通常把 Java 堆分爲新生代和老年代,這樣就能夠根據各個年代的特色採用最適當的收集算法。在新生代中,大量的對象都是「朝生夕死」,每次垃圾回收時,均可以發現大量對象死去,因此針對新生代的垃圾回收通常選擇複製算法。只須要複製少許存活對象就能夠完成收集。針對老年代的垃圾回收,對象的存活時間較長,就必須使用標記-清除或者標記-整理算法來進行回收。
在新生代中,絕大多數的對象都是「朝生夕死」的,新生代並不須要按照 1:1 的比例劃份內存空間,而是將內存分爲一個較大的 Eden 空間和一個較小的 Survivor 空間,並將 Survivor 空間分紅兩個較小空間,分別是 From Space 和 ToSpace。每次使用 Eden 空間和其中的一塊 Survivor 空間,當進行回收時,將該兩塊空間中還存活的對象複製到另外一塊 Survivor 空間中。Hotspot 虛擬機默認 Eden 和 Survivor 的大小比例是 8:1,也就是每次新生代可用內存空間爲整個新生代容量的 90%。
這裏很顯然會有一個問題,理論上每次新生代 GC 都會回收絕大多數的對象,可是沒法保證 GC 存活後的對象大學都不超過整個新生代的 10%。當 Survivor 空間的內存不夠用是,就須要老年代作內存擔保(分配擔保策略,前邊兩篇文章有提過,讀者可自行查閱)。一樣用餐廳的理論來理解,你但願把 A 廳的顧客轉移到 B 廳,可是 B 廳已經沒有足夠空間容納全部顧客了,這時候能夠選擇將顧客安置在 VIP 包廂【老年代】。而且每次在新生代 GC 中存活的對象,其年齡就會 +1,默認狀況下年齡達到 15 的對象會被轉移到老年代。
這裏也能夠簡單理解爲咱們給餐廳的忠實吃貨辦了張 VIP 卡... ...
因此,同窗,辦卡嗎?辦卡享五折優惠哈!
... ...
《深刻理解Java虛擬機》周志明 著