(我在知乎的專欄文章地址: https://zhuanlan.zhihu.com/p/... )程序員
C/C++等語言中須要手動管理內存,操做繁瑣,還容易忘記釋放內存。
爲了把程序員從這些繁瑣的操做中解放出來,因此引入了GC。
GC的主要工做就是尋找再也不須要的對象,釋放其內存。這句話中蘊含着兩個操做:算法
每一個對象都有一個變量,記錄了本身被引用的次數。每被引用一次,引用次數加一。相反,再也不被引用時,引用計數減一。當引用次數爲0的時候,說明對象須要被回收。併發
優勢:實現簡單線程
缺點:沒法解決循環引用指針
改進:對象
基於可達性(reachable)分析。從被稱爲GC Roots的一些對象出發,找到其引用的對象,再到其間接引用的對象,造成一條引用鏈。凡是不在引用鏈裏面的對象,被稱爲不可達(Unreachable)對象,被標記爲須要回收。內存
優勢: 目前主流的GC算法,解決了引用計數的問題。
缺點:實現較爲複雜ci
標記清除算法分爲「標記」和「清除」兩個階段:首先標記出須要回收的對象,標記完成以後統一清除對象。它的優勢是效率高,缺點是容易產生內存碎片。rem
它將可用內存容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊用完以後,就將還存活的對象複製到另一塊上面,而後在把已使用過的內存空間一次理掉。它的優勢是實現簡單,效率高,不會存在內存碎片。缺點就是須要2倍的內存來管理。get
標記操做和「標記-清理」算法一致,後續操做不僅是直接清理對象,而是在清理無用對象完成後讓全部 存活的對象都向一端移動,並更新引用其對象的指針。由於要移動對象,因此它的效率要比「標記-清理」效率低,可是不會產生內存碎片。
標記-整理和複製算法是對標記-清除算法的改進,解決了一些標記-清除算法的缺點。可是並不意味着後兩種算法優於標記-清除算法,只是有所取捨,在工程上權衡。
分代不是一種新的算法,而是對已有的算法的工程上調優。
因爲對象的存活時間有長有短,因此對於存活時間長的對象,減小被gc的次數能夠避免沒必要要的開銷。這樣咱們就把內存分紅新生代和老年代,新生代存放剛建立的和存活時間比較短的對象,老年代存放存活時間比較長的對象。這樣每次僅僅清理年輕代,老年代僅在必要時時再作清理能夠極大的提升GC效率,節省GC時間。
Serial -XX:+UseSerialGC
Parallel -XX:+UseParallelGC -XX:+UseParallelOldGC
CMS -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
G1 -XX:+UseG1GC
默認gc,分代gc,經典的Eden, Survivor, OldGen, PermGen。
1.8中PerGen被廢棄,部分被MetaSpace代替。
改進的mark-sweep算法。
年輕代使用Parallel,老年代才使用CMS。能夠經過參數配置不一樣的回收器。
初始標記(CMS-initial-mark stop the world) -> 併發標記(CMS-concurrent-mark) -> 從新標記(CMS-remark stop the world) -> 併發清除(CMS-concurrent-sweep) ->併發重設狀態等待下次CMS的觸發(CMS-concurrent-reset)
多個Region, 每一個Region都有Eden,Survivor,Old,Humongous。
由於劃分多個Region,因此單個Region可能比較小,對於那些較大的對象用Humongous儲存
對象分配策略TLAB(Thread Local Allocation Buffer)線程本地分配緩衝區Eden區Humongous區TLAB是爲了不同步的預分配區。