垃圾回收就是回收內存中再也不使用的對象。java
步驟有2步:算法
1. 查找內存中再也不使用的對象併發
(1)引用計數法:有一個缺點,不能檢測到環的存在oracle
(2)根搜索算法:經過一系列名爲「GC Roots」的對象做爲起始點,當一個對象到GC Roots沒有任何引用鏈相連時,則證實此對象是不可用的性能
2.釋放這些對象佔用的內存線程
(1) 標記-複製 :它將可用內存容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊用完以後,就將還存活的對象複製到另一塊上面,而後在把已使用過的內存空間一次理掉。它的優勢是實現簡單,效率高,不會存在內存碎片。缺點就是須要2倍的內存來管理。設計
(2) 標記-清理:清除算法分爲「標記」和「清除」兩個階段:首先標記出須要回收的對象,標記完成以後統一清除對象。它的優勢是效率高,缺點是容易產生內存碎片。指針
(3) 標記-整理:標記操做和「標記-清理」算法一致,後續操做不僅是直接清理對象,而是在清理無用對象完成後讓全部 存活的對象都向一端移動,並更新引用其對象的指針。由於要移動對象,因此它的效率要比「標記-清理」效率低,可是不會產生內存碎片。對象
新生代和老生代:blog
因爲對象的存活時間有長有短,因此對於存活時間長的對象,減小被gc的次數能夠避免沒必要要的開銷。這樣咱們就把內存分紅新生代和老年代,新生代存放剛建立的和存活時間比較短的對象,老年代存放存活時間比較長的對象。這樣每次僅僅清理年輕代,老年代僅在必要時時再作清理能夠極大的提升GC效率,節省GC時間。
java垃圾收集器的歷史:
1. Serial(串行)收集器
2. Parallel(並行)收集器
3. CMS(併發)收集器
4. G1(併發)收集器
(1)程序調用System.gc時能夠觸發;
(2)系統自身來決定GC觸發的時機。系統判斷GC觸發的依據:根據Eden區和From Space區的內存大小來決定。當內存大小不足時,則會啓動GC線程並中止應用線程。
oracle官方計劃在jdk9中將G1變成默認的垃圾收集器,以替代CMS。
G1的設計原則就是簡單可行的性能調休。將新生代,老生代的物理空間劃分取消了。
細節:
G1算法將堆劃分爲若干個區域(Region),它仍然屬於分代收集器。不過,這些區域的一部分包含新生代,新生代的垃圾收集依然採用暫停全部應用線程的方式,將存活對象拷貝到老年代或者Survivor空間。老年代也分紅不少區域,G1收集器經過將對象從一個區域複製到另一個區域,完成了清理工做。這就意味着,在正常的處理過程當中,G1完成了堆的壓縮(至少是部分堆的壓縮),這樣也就不會有cms內存碎片問題的存在了。
在G1中,還有一種特殊的區域,叫Humongous區域。 若是一個對象佔用的空間超過了分區容量50%以上,G1收集器就認爲這是一個巨型對象。這些巨型對象,默認直接會被分配在年老代,可是若是它是一個短時間存在的巨型對象,就會對垃圾收集器形成負面影響。爲了解決這個問題,G1劃分了一個Humongous區,它用來專門存放巨型對象。若是一個H區裝不下一個巨型對象,那麼G1會尋找連續的H分區來存儲。爲了能找到連續的H區,有時候不得不啓動Full GC。
PS:在java 8中,持久代也移動到了普通的堆內存空間中,改成元空間。
最後,G1提供了兩種GC模式,Young GC和Mixed GC,兩種都是Stop The World(STW)的。