市面上有關JVM垃圾回收的文章不少,有些是針對垃圾收集器,有些是介紹垃圾回收算法,也有些各方面都有涉及。本文但願能作一個比較全面的總結,最關鍵的是造成本身的語言,有本身的理解和沉澱。html
你們都知道,java語言的內存是動態分配的,不像C++語言還須要開發者專門干預,在必定程度上能夠提升開發效率。那麼你們可能疑問:既然不須要咱們開發者關心,咱們爲何還要討論?做爲一個程序語言的駕馭者,必然須要掌握該語言的方方面面,包括底層的原理和機制。
Java語言使用了內存動態分配和垃圾回收技術,掌握這些不只能夠提升本身的逼格,並且爲後續的JVM調優打下紮實的基礎,讓本身離架構師更近一步。java
JVM的內存結構包括五大區域:程序計數器、虛擬機棧、本地方法棧、堆區、方法區。其中程序計數器、虛擬機棧、本地方法棧3個區域隨線程而生、隨線程而滅,所以這幾個區域的內存分配和回收都具有肯定性,就不須要過多考慮回收的問題,由於方法結束或者線程結束時,內存天然就跟隨着回收了。而Java堆區和方法區則不同,這部份內存的分配和回收是動態的,正是垃圾收集器所需關注的部分。
垃圾收集器在對堆區和方法區進行回收前,首先要肯定這些區域的對象哪些能夠被回收,哪些暫時還不能回收,這就要用到判斷對象是否存活的算法。算法
一、引用計數法多線程
在這種方法中,堆中每一個對象實例都有一個引用計數。任何引用計數器爲0的對象實例能夠被看成垃圾收集。
引用計數是垃圾收集器中的早期策略。該方法看似很實用,可是解決不了循環引用的問題(好比循環鏈表)。架構
二、可達性分析算法併發
從一個節點GC ROOT開始,尋找對應的引用節點,而後尋該引用節點的引用節點,當全部的引用節點尋找完畢以後,剩餘沒有被引用的節點將會被斷定爲是可回收的對象。佈局
三、引用分類spa
在Java語言中,將引用又分爲強引用、軟引用、弱引用、虛引用四種,這四種引用強度依次逐漸減弱。垃圾回收算法都是基於強引用而言的。.net
一、標記-清除算法線程
標記-清除算法從根集合(GC Roots)開始掃描,對須要繼續存活的對象進行標記,標記完畢後,再掃描整個空間中未被標記的對象,進行回收,以下圖所示。
標記-清除算法只需對不須要存活的對象進行處理,在存活對象比較多的狀況下極爲高效,可是會形成內存碎片。
二、複製算法
複製算法的提出就是爲了解決內存碎片的問題,以下圖所示。複製算法雖然解決了內存碎片的問題,可是浪費一半內存。另外在對象存活率很高的時候,複製成本會很是高。
三、標記-整理算法
標記-整理算法是在標記-清除算法的基礎上,又進行了對象的移動,所以成本更高,可是卻解決了內存碎片的問題。具體流程見下圖:
四、分代收集算法
通常狀況下將堆區劃分爲老年代(Tenured Generation)和新生代(Young Generation),老年代的特色是每次垃圾收集時只有少許對象須要被回收,而新生代的特色是每次垃圾回收時都有大量的對象須要被回收,那麼就能夠根據不一樣代的特色採起最適合的收集算法。
新生代採用複製算法;老年代採用標記-整理算法。
其中年輕代內存分配過程以下:
1) 絕大多數剛建立的對象會被分配在Eden區,其中的大多數對象很快就會消亡;
2) 最初一次,當Eden區滿的時候,執行Minor GC,將消亡的對象清理掉,並將剩餘的對象複製到一個存活區Survivor0;
3) 下次Eden區滿了,再執行一次Minor GC,將消亡的對象清理掉,將存活的對象複製到Survivor1中,而後清空Eden區;
4) 將Survivor0中消亡的對象清理掉,將其中能夠晉級的對象晉級到Old區,將存活的對象也複製到Survivor1區,而後清空Survivor0區;
5) 而後跳到第三步,當兩個存活區切換了幾回(HotSpot虛擬機默認15次,用-XX:MaxTenuringThreshold控制)以後,仍然存活的對象,將被複制到老年代。
一、新生代收集器
1) Serial收集器
單線程收集器
2) ParaNew收集器
Serial收集器的多線程版,關注縮短垃圾收集時間。(使用-XX:+UseParNewGC開關來控制使用ParNew+Serial Old收集器組合收集內存;使用-XX:ParallelGCThreads來設置執行內存回收的線程數。)
3) Parallel Scavenge收集器
關注CPU吞吐量,即運行用戶代碼的時間/總時間。(使用-XX:+UseParallelGC開關控制使用Parallel Scavenge+Serial Old收集器組合回收垃圾(這也是在Server模式下的默認值);使用-XX:GCTimeRatio來設置用戶執行時間佔總時間的比例,默認99,即1%的時間用來進行垃圾回收;使用-XX:MaxGCPauseMillis設置GC的最大停頓時間;使用-XX:+UseAdaptiveSizePolicy能夠進行動態控制Eden/Survivor比例,老年代對象年齡,新生代大小等。)
二、老年代收集器
1) Serial Old收集器
單線程收集器
2) Parallel Old收集器
Parallel Scavenge收集器的老年代版本(使用-XX:+UseParallelOldGC開關控制使用Parallel Scavenge +Parallel Old組合收集器進行收集。)
3) CMS收集器
多線程,優勢是併發收集(用戶線程能夠和GC線程同時工做)
三、G1收集器
特性:
1) 首先收集儘量多的垃圾(Garbage First)
內部採用了啓發式算法,找出具備高收集收益的分區進行收集。
2) 並行和併發
和CMS類似,能夠作到用戶線程和GC線程同時工做。
3) 內存佈局調整
將整個堆劃分爲多個大小相等的獨立區域(Region),新生代和老年代再也不是物理隔離,它們都是一部分Region(不須要連續)的集合。每一個分區均可能隨G1的運行在不一樣代之間先後切換。
G1劃分了一個Humongous區,它用來專門存放巨型對象。
4) GC模式
G1提供了兩種GC模式,Young GC和Mixed GC,兩種都是Stop The World(STW)的。
[1] https://blog.csdn.net/ft30597...
[2] https://www.cnblogs.com/1024C...
[3] https://blog.csdn.net/x_i_y_u...
[4] https://www.jianshu.com/p/e99...
[5] https://blog.csdn.net/foolish...
[6] https://blog.csdn.net/coderli...
[7] https://www.cnblogs.com/ASPNE...