Java GC是在何時,對什麼東西,作了什麼事情?」程序員
什麼位置:大部分在堆中,還有方法區!!方法區的垃圾收集主要回收兩部份內容:廢棄常量和無用的類,當滿了以後一樣觸發FullGC, HotSpot1.8以前由永久代實現,1.8已經移到元空間,元空間並不在虛擬機中,而是使用本地內存。算法
何時:程序員不能控制具體時間,系統在不可預測的時間調用System.gc()函數的時候;固然能夠經過調優,用NewRatio控制newObject和oldObject的比例,用MaxTenuringThreshold 控制進入oldObject的次數,使得oldObject 存儲空間延遲達到full gc,從而使得計時器引起gc時間延遲OOM的時間延遲,以延長對象生存期。併發
什麼東西:超出了做用域或引用計數爲空的對象;從gc root開始搜索找不到的對象,並且通過一次標記、清理,仍然沒有復活的對象。ide
什麼事情:刪除不使用的對象,回收內存空間;運行默認的finalize,固然程序員想馬上調用就用dipose調用以釋放資源如文件句柄,JVM用from survivor、to survivor對它進行標記清理,對象序列化後也可使它復活。函數
引用計數法(ReferenceCounting):給對象中添加一個引用計數器,每當它被引用到一個地方時,計數器值就+1,;當引用失效時,計數器值就-1;任什麼時候刻計數器爲0的對象就是不可能在被使用。spa
1)、優勢.net
斷定效率很高線程
(2)、缺點xml
不會徹底準確,由於若是出現兩個對象相互引用的問題就不行了。對象
就像JVM問A能夠被回收不,A說我被B引用去問B;
JVM問B能夠被回收不,B說我被A引用去問A。
如今虛擬機都不採用引用計數法。
可達性分析法:該方法的基本思想是經過一系列的「GC Roots」對象(局部變量,棧等)做爲起點進行搜索,若是在「GC Roots」和一個對象之間沒有可達路徑,則稱該對象是不可達的,不過要注意的是被斷定爲不可達的對象不必定就會成爲可回收對象;被斷定爲不可達的對象要成爲可回收對象必須至少經歷兩次標記過程,若是在這兩次標記過程當中仍然沒有逃脫成爲可回收對象的可能性,則基本上就真的成爲可回收對象了。
可達性分析期間須要保證整個執行系統的一致性,對象的引用關係不能發生變化,因此須要將用戶的正常的工做線程所有停掉,避免對象的引用關係變化,與可達性分析不一致;
致使GC進行時必須停頓全部Java執行線程(稱爲"Stop The World");(幾乎不會發生停頓的CMS收集器中,枚舉GC ROOTS時也是必需要停頓的)
是JVM在後臺自動發起和自動完成的;
在用戶不可見的狀況下,把用戶正常的工做線程所有停掉;
標記-清除(Mark-Sweep)算法:兩個階段:標記階段和清除階段。標記階段的任務是根據GC ROOTS標記出全部須要被回收的對象,清除階段就是回收被標記的對象所佔用的空間;標記-清除算法實現起來比較容易,可是有一個比較嚴重的問題就是容易產生內存碎片,碎片太多可能會致使後續過程當中須要爲大對象分配空間時沒法找到足夠的空間而提早觸發新的一次垃圾收集動做。
複製算法:它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活着的對象複製到另一塊上面,而後再把已使用的內存空間一次清理掉,這樣一來就不容易出現內存碎片的問題。
標記-整理算法:應用在老年代。該算法標記階段和Mark-Sweep同樣,可是在完成標記以後,它不是直接清理可回收對象,而是將存活對象都向一端移動,而後清理掉端邊界之外的內存。在清理的時候,把全部 存活 對象扎堆到同一個地方,讓它們待在一塊兒,這樣就沒有內存碎片了。
分代收集算法(目前經常使用):應用在年輕代。根據對象存活的生命週期將內存劃分爲若干個不一樣的區域,通常來講是將新生代劃分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將Eden和Survivor中還存活的對象複製到另外一塊Survivor空間中,而後清理掉Eden和剛纔使用過的Survivor空間。
分代收集算法總結:
(1)在年輕代中,Eden區提供堆內存若是滿了,Eden進行MinorGC,將存活的對象→Survivor A中,Eden區清空;
(2)Eden區再次滿, Eden 區和 Survivor A 區同時進行 Minor GC,把存活對象放入 Survivor B 區,Eden和Survivor A同時清空;
(3)重複(2)的操做,若是當某個 Survivor 區被填滿,且仍有對象未被複制完畢時,或者某些對象在反覆 Survive 15 次左右時,或者大對象,則把這部分剩餘對象放到Old 區(老年代);
(4)當 Old 區也被填滿時,進行 Full GC,對 Old 區進行垃圾回收。
[注意,在真實的 JVM 環境裏,能夠經過參數 SurvivorRatio 手動配置 Eden 區和單個 Survivor 區的比例,默認爲 8。能夠經過參數–XX:SurvivorRatio 來設定,即將堆內存中年輕代劃分爲8:1:1]
CMS(Concurrent Mark-Sweep Collector)收集器是一種以獲取最短回收停頓時間爲目標的收集器,它是一種併發收集器,採用的是Mark-Sweep算法。
一種以獲取最短回收停頓時間爲目標的收集器 「標記-清除」,有 4 個過程:
初始標記(查找直接與 gc roots 連接的對象),須要「Stop The World」;
併發標記(GC Roots Tracing 過程:查找與gc roots非直接相連的對象,以GCRoots的對象做爲起始點,從這個節點向下搜索,搜索走過的路徑稱爲ReferenceChain,當一個對象到GCRoots沒有任何ReferenceChain相連時,這個對象不可到達,則證實這個對象不可用);
從新標記(因 爲併發標記時有用戶線程在執行,標記結果可能有變化),須要「Stop The World」 ;
併發清除(併發清除階段會清除對象)。
其中初始標記和從新標記階段,要「stop the world」(中止工做線程)。
優勢:併發收集,低停頓
缺點:
1)不 能處理浮動垃圾
2)對 cpu 資源敏感,佔用CPU資源較大。CMS默認啓動的回收線程數是(CPU數量+3)/ 4,也就是當CPU在4個以上時,併發回收時垃圾收集線程很多於25%的CPU資源,而且隨着CPU數量的增長而降低。可是當CPU不足4個(譬如2個)時,CMS對用戶程序的影響就可能變得很大。
3)產生大量內存碎片
G1收集器是面向服務端應用的收集器,它能充分利用多CPU、多核環境。
所以它是一款並行與併發收集器,而且它能創建可預測的停頓時間模型。
對垃圾回收進行了劃分優先級的操做,這種有優先級的區域回收方式保證了它的高效率;最大的優勢是結合了空間整合,不會產生大量的碎片,也下降了進行gc的頻率,讓使用者明確指定停頓時間。
初始標記(Initial Marking)
初始標記階段僅僅只是標記一下GC Roots能直接關聯到的對象,而且修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序併發運行時,能在正確可用的Region中建立新對象,這階段須要停頓線程,但耗時很短。
併發標記(Concurrent Marking)
併發標記階段是從GC Root開始對堆中對象進行可達性分析,找出存活的對象,這階段耗時較長,但可與用戶程序併發執行。
最終標記(Final Marking)
最終標記階段是爲了修正在併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分標記記錄,虛擬機將這段時間對象變化記錄在線程Remembered Set Logs裏面,最終標記階段須要把Remembered Set Logs的數據合併到Remembered Set中,這階段須要停頓線程,可是可並行執行。
篩選回收(Live Data Counting and Evacuation)
篩選回收階段首先對各個Region的回收價值和成本進行排序,根據用戶所指望的GC停頓時間來制定回收計劃,這個階段其實也能夠作到與用戶程序一塊兒併發執行,可是由於只回收一部分Region,時間是用戶可控制的,並且停頓用戶線程將大幅提升收集效率。
https://baijiahao.baidu.com/s?id=1583441733083989684&wfr=spider&for=pc
http://blog.csdn.net/cy609329119/article/details/51771953
https://blog.csdn.net/xiaomingdetianxia/article/details/77446762