GC(Garbage Collection)垃圾回收,釋放垃圾佔用的空間,對堆中已經死亡或者長時間沒有使用的對象進行清除和回收,防止內存泄漏。能夠有效使用內存空間。算法
垃圾收集以前須要定義什麼是垃圾,以後才能決定如何回收垃圾。數組
拋開書面上介紹的幾種垃圾分析算法,一步到位說下jvm採用的可達性分析法。jvm
基本思路是經過根引用(GC ROOT)做爲分析起點,沿着節點向下搜索,搜索路徑稱爲引用鏈(Reference Chain),當一個對象到GC ROOT沒有任何引用鏈時,證實對象再也不使用(GC ROOT到對象節點不可達)。設計
經過可達性分析算法能夠解決引用計數沒法解決的「循環依賴」,只要對象和GC ROOT之間沒法創建直接或者間接的連接,就能夠認定爲可回收對象。對象
既然GC ROOT在對象可達性分析時如此重要,那麼哪些對象能夠做爲GC ROOT呢?blog
在以前須要先了解下JVM的內部結構:生命週期
如下四種狀況能夠認定爲GC ROOT:內存
在肯定垃圾以後就能夠進行垃圾回收了,回收過程當中最重要的一點就是如何高效的回收,這些也都是不一樣版本回收器進化的主要目標。虛擬機
常見的垃圾收集算法:io
標記清除
標記清除(Mark-Sweep)是將內存中認定爲垃圾的對象進行標記,以後對這些標記的對象進行清理,清理以後的空間能夠給新對象使用。
可是這種操做算法存在的問題會存在大量不連續的清理空間,也就是內存碎片。內存碎片帶來的問題是,有的時候咱們進行對象分配時,須要連續的內存(好比數組這種)可是因爲內存中沒有足夠的聯繫內存,致使碎片內存用不了,形成了內存空間的浪費。
複製算法
複製(Copying)是在標記清除之上演進而來的,主要目的是解決內存碎片問題,將可用內存空間按照容量進行劃分紅大小相等的兩塊,每次只是用其中一塊,當這部份內存使用完成以後,能夠把存活對象複製到另外一塊上面,把以前使用的內存進行一次性清理,保證內存空間連續可用,複製算法咱們能夠不考慮內存碎片等問題,分配過程更簡單高效。
可是複製算法帶來的就是空間的代價更大。
標記整理
既然標記清除,複製算法都存在一些明確的短板,是否能夠針對這些短板設計一個回收算法呢?因而就有了標記整理算法(Mark-Compact)。
標記整理過程和標記清除算法同樣,可是後續整理方式是將存活對象統一移動到內存到一側,在進行邊界外的對象清除。
這種算法屬於標記清除算法的升級版本,能夠解決內存碎片問題,也避免了複製算法存在一半空間浪費的問題,可是也不是沒有問題。首先他會形成更多的內存變更,好比須要判斷存活對象,整理存活對象地址,效率上對於複製算法來講要差不少。
咱們瞭解了三種收集算法,JVM內存回收就能夠根據本身特色進行算法選擇了。
好比JVM根據對象存活週期不一樣將內存劃分紅不一樣的幾部分。好比堆中針對於快生快消特色分出了新生代,存活較久對象分出了老年代。因而針對不一樣代對象特色能夠選擇不一樣的回收算法,好比年輕代對象生命週期比較短,可選擇複製算法減小標記整理的代價。老年代存活對象較多,空間利用率上相對要求較高,須要使用標記清理或者標識整理算法。
那麼JVM中對象具體是怎麼分配的呢?從內存模型講起。
堆是內存中最大的一塊,也是垃圾回收的主要戰場。
堆主要分爲兩個區域:年輕代和老年代,年輕代又分爲Eden,s1,s2區。
Eden
新生對象優先在Eden中分配,當Eden中沒有足夠空間後,會觸發一次YGC(比較討厭用Minor GC和Major GC的說法),YGC以後Eden區被回收,無需回收的對象進入S1區,若是S1區容不下則直接進入老年代。
S區
S區主要做用是做爲Eden和Old之間的緩衝帶,由於以前說過Eden大部分對象都是短生命的,因此爲了不YGC以後直接進入老年代,引入S區也是有必要的,緩衝了由於頻繁YGC使得老年代被填滿的風險。
由於一而再再而三以後大部分對象仍是在新生代消亡了,因此設置一個S區是明智的。
通常對象須要通過15(默認)YGC以後才進入老年代。
而兩個S區的目的就是爲了採用複製算法,來解決碎片問題。若是一個區域的話你就只能採起標記整理或標記清除算法了,爲了下降YGC期間(由於YGC太頻繁了)對於程序的影響,用複製算法這種簡單可依賴的方式還有有必要的。
若是分紅好幾個S區會有什麼問題呢?頻繁的複製是個問題,過多的S區空間形成總體空間利用率更低也是個問題,相信這個2的閾值也是通過屢次實驗得來的,因此GC的不少默認算法實際上是很優的配置,除非結合本身業務特色,不然比建議進行修改。
Old區
默認老年代佔用整個區的2/3,只有發生Full GC(這個說法也不許確,咱們用CMS回收器,因此就稱爲CMS GC吧)時才進行整理,Full GC會形成STW,內存越大STW確定時間就越長(這個也是咱們調優JVM參數一個很重要的參考點),因此內存並非越大越好。上面說了老年代存在大量長期對象,因此採用標記算法更合適。
哪些對象會進入老年代?