Jvm垃圾回收目前就準備了這三篇博文進行整理,在寫博文的過程當中我也是邊看邊記載的,我以爲這種學習方式更容易讓人記住,不會輕易忘記。之前的學習模式都是看PDF文檔、看書等,可是有個缺點就是當時記住了過段時間就會忘記,所以想把學習過程當中重要的部分作個筆記總結,以便於後期複習回顧(學習技巧僅我的觀點)同時也但願lz的博客能幫助到廣大園友一丟丟。在此立個Flag!之後我會堅持寫博客的。哈哈--好了 接下來言歸正傳。html
第一篇《Jvm垃圾回收器(基礎篇)》主要講述了判斷對象的生死?兩種基礎判斷對象生死的算法、引用計數法、可達性分析算法,方法區的回收。在第二篇《Jvm垃圾回收器(算法篇)》中主要介紹了垃圾回收的幾種經常使用算法:標記-清除、複製算法、標記-整理算法、分代收集算法。那麼接下來咱們重點研究Jvm的垃圾收集器(serial收集器、parnew收集器、parallel scavenge收集器、serial old 收集器、parallel old收集器、cms收集器、g1收集器)。前面說了那麼多就是爲它作鋪墊的。web
正式進入前先看下圖解HotSpot虛擬機所包含的收集器:算法
圖中展現了7種做用於不一樣分代的收集器,若是兩個收集器之間存在連線,則說明它們能夠搭配使用。虛擬機所處的區域則表示它是屬於新生代仍是老年代收集器。多線程
新生代收集器:Serial、ParNew、Parallel Scavenge併發
老年代收集器:CMS、Serial Old、Parallel Oldpost
整堆收集器: G1性能
並行收集:指多條垃圾收集線程並行工做,但此時用戶線程仍處於等待狀態。學習
併發收集:指用戶線程與垃圾收集線程同時工做(不必定是並行的可能會交替執行)。用戶程序在繼續運行,而垃圾收集程序運行在另外一個CPU上。url
吞吐量:即CPU用於運行用戶代碼的時間與CPU總消耗時間的比值(吞吐量 = 運行用戶代碼時間 / ( 運行用戶代碼時間 + 垃圾收集時間 ))。例如:虛擬機共運行100分鐘,垃圾收集器花掉1分鐘,那麼吞吐量就是99%spa
Serial收集器是最基本的、發展歷史最悠久的收集器。
特色:單線程、簡單高效(與其餘收集器的單線程相比),對於限定單個CPU的環境來講,Serial收集器因爲沒有線程交互的開銷,專心作垃圾收集天然能夠得到最高的單線程手機效率。收集器進行垃圾回收時,必須暫停其餘全部的工做線程,直到它結束(Stop The World)。
應用場景:適用於Client模式下的虛擬機。
Serial / Serial Old收集器運行示意圖
ParNew收集器其實就是Serial收集器的多線程版本。
除了使用多線程外其他行爲均和Serial收集器如出一轍(參數控制、收集算法、Stop The World、對象分配規則、回收策略等)。
特色:多線程、ParNew收集器默認開啓的收集線程數與CPU的數量相同,在CPU很是多的環境中,可使用-XX:ParallelGCThreads參數來限制垃圾收集的線程數。
和Serial收集器同樣存在Stop The World問題
應用場景:ParNew收集器是許多運行在Server模式下的虛擬機中首選的新生代收集器,由於它是除了Serial收集器外,惟一一個能與CMS收集器配合工做的。
ParNew/Serial Old組合收集器運行示意圖以下:
與吞吐量關係密切,故也稱爲吞吐量優先收集器。
特色:屬於新生代收集器也是採用複製算法的收集器,又是並行的多線程收集器(與ParNew收集器相似)。
該收集器的目標是達到一個可控制的吞吐量。還有一個值得關注的點是:GC自適應調節策略(與ParNew收集器最重要的一個區別)
GC自適應調節策略:Parallel Scavenge收集器可設置-XX:+UseAdptiveSizePolicy參數。當開關打開時不須要手動指定新生代的大小(-Xmn)、Eden與Survivor區的比例(-XX:SurvivorRation)、晉升老年代的對象年齡(-XX:PretenureSizeThreshold)等,虛擬機會根據系統的運行情況收集性能監控信息,動態設置這些參數以提供最優的停頓時間和最高的吞吐量,這種調節方式稱爲GC的自適應調節策略。
Parallel Scavenge收集器使用兩個參數控制吞吐量:
XX:MaxGCPauseMillis 控制最大的垃圾收集停頓時間
XX:GCRatio 直接設置吞吐量的大小。
Serial Old是Serial收集器的老年代版本。
特色:一樣是單線程收集器,採用標記-整理算法。
應用場景:主要也是使用在Client模式下的虛擬機中。也可在Server模式下使用。
Server模式下主要的兩大用途(在後續中詳細講解···):
Serial / Serial Old收集器工做過程圖(Serial收集器圖示相同):
是Parallel Scavenge收集器的老年代版本。
特色:多線程,採用標記-整理算法。
應用場景:注重高吞吐量以及CPU資源敏感的場合,均可以優先考慮Parallel Scavenge+Parallel Old 收集器。
Parallel Scavenge/Parallel Old收集器工做過程圖:
一種以獲取最短回收停頓時間爲目標的收集器。
特色:基於標記-清除算法實現。併發收集、低停頓。
應用場景:適用於注重服務的響應速度,但願系統停頓時間最短,給用戶帶來更好的體驗等場景下。如web程序、b/s服務。
CMS收集器的運行過程分爲下列4步:
初始標記:標記GC Roots能直接到的對象。速度很快可是仍存在Stop The World問題。
併發標記:進行GC Roots Tracing 的過程,找出存活對象且用戶線程可併發執行。
從新標記:爲了修正併發標記期間因用戶程序繼續運行而致使標記產生變更的那一部分對象的標記記錄。仍然存在Stop The World問題。
併發清除:對標記的對象進行清除回收。
CMS收集器的內存回收過程是與用戶線程一塊兒併發執行的。
CMS收集器的工做過程圖:
CMS收集器的缺點:
一款面向服務端應用的垃圾收集器。
特色以下:
並行與併發:G1能充分利用多CPU、多核環境下的硬件優點,使用多個CPU來縮短Stop-The-World停頓時間。部分收集器本來須要停頓Java線程來執行GC動做,G1收集器仍然能夠經過併發的方式讓Java程序繼續運行。
分代收集:G1可以獨自管理整個Java堆,而且採用不一樣的方式去處理新建立的對象和已經存活了一段時間、熬過屢次GC的舊對象以獲取更好的收集效果。
空間整合:G1運做期間不會產生空間碎片,收集後能提供規整的可用內存。
可預測的停頓:G1除了追求低停頓外,還能創建可預測的停頓時間模型。能讓使用者明確指定在一個長度爲M毫秒的時間段內,消耗在垃圾收集上的時間不得超過N毫秒。
G1爲何能創建可預測的停頓時間模型?
由於它有計劃的避免在整個Java堆中進行全區域的垃圾收集。G1跟蹤各個Region裏面的垃圾堆積的大小,在後臺維護一個優先列表,每次根據容許的收集時間,優先回收價值最大的Region。這樣就保證了在有限的時間內能夠獲取儘量高的收集效率。
G1與其餘收集器的區別:
其餘收集器的工做範圍是整個新生代或者老年代、G1收集器的工做範圍是整個Java堆。在使用G1收集器時,它將整個Java堆劃分爲多個大小相等的獨立區域(Region)。雖然也保留了新生代、老年代的概念,但新生代和老年代再也不是相互隔離的,他們都是一部分Region(不須要連續)的集合。
G1收集器存在的問題:
Region不多是孤立的,分配在Region中的對象能夠與Java堆中的任意對象發生引用關係。在採用可達性分析算法來判斷對象是否存活時,得掃描整個Java堆才能保證準確性。其餘收集器也存在這種問題(G1更加突出而已)。會致使Minor GC效率降低。
G1收集器是如何解決上述問題的?
採用Remembered Set來避免整堆掃描。G1中每一個Region都有一個與之對應的Remembered Set,虛擬機發現程序在對Reference類型進行寫操做時,會產生一個Write Barrier暫時中斷寫操做,檢查Reference引用對象是否處於多個Region中(即檢查老年代中是否引用了新生代中的對象),若是是,便經過CardTable把相關引用信息記錄到被引用對象所屬的Region的Remembered Set中。當進行內存回收時,在GC根節點的枚舉範圍中加入Remembered Set便可保證不對全堆進行掃描也不會有遺漏。
若是不計算維護 Remembered Set 的操做,G1收集器大體可分爲以下步驟:
初始標記:僅標記GC Roots能直接到的對象,而且修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序併發運行時,能在正確可用的Region中建立新對象。(須要線程停頓,但耗時很短。)
併發標記:從GC Roots開始對堆中對象進行可達性分析,找出存活對象。(耗時較長,但可與用戶程序併發執行)
最終標記:爲了修正在併發標記期間因用戶程序執行而致使標記產生變化的那一部分標記記錄。且對象的變化記錄在線程Remembered Set Logs裏面,把Remembered Set Logs裏面的數據合併到Remembered Set中。(須要線程停頓,但可並行執行。)
篩選回收:對各個Region的回收價值和成本進行排序,根據用戶所指望的GC停頓時間來制定回收計劃。(可併發執行)
G1收集器運行示意圖:
-- 結束-- JVM垃圾收集暫告一段落。