垃圾回收歷史,早在Lisp 就有了垃圾收集的功能.垃圾收集的問題主要在三個地方:哪些對象須要回收,在何時回收對象,如何回收對象.
java
一.哪些對象須要回收算法
判斷哪些對象須要回收的算法主要有兩種,引用計數算法,可達性分析算法.
多線程
1.引用計數算法:
線程
一個變量引用一個對象的時候,該對象的引用計數器就加1,有多少個變量引用對象,那這個對象的引用計數器就是多少,少一個引用的時候就減1.直到引用計數器變成0,就成爲可回收對象.
對象
2.可達性分析算法
內存
從一個名爲ROOTGC出發遍歷,只要從ROOTGC經過對象內的引用沒法到達的對象就是可回收對象.能夠選擇類變量做爲ROOTGC.
虛擬機
關於Java中的引用,java中分爲強引用,軟引用,弱引用,虛引用.效率
強引用:就是A a = new A();
變量
軟引用: 內存回收以前對軟引用的對象進行回收 SoftReference
互聯網
弱引用:下次垃圾回收必定會執行到. WeakReference
虛引用:沒法經過虛引用去獲取對象,只能在對象被回收的時候收到系統的一個通知.
二.怎麼回收
垃圾回收算法:標記清除算法,複製算法,標記整理算法,分代算法
1.標記清理算法: 標記兩次,第二次標記完成以後就清理,標記效率低下,會產生大量內存碎片.
如圖所示,紅色是沒被標記內存,灰色是標記內存.,第二次編輯完成以後清除灰色區域,而後會有很 多不連續的內存碎片.
2.複製算法
將內存分爲兩塊,對象只放其中一塊上面,在須要回收的時候,把全部對象移動到另外一塊內存上.而後回收以前的那塊內存.有人通過分析,Eden:Survivor Fron:To = 8:1:1是比較合理的狀況.
3.標記整理算法
將非標記的對象移動到一塊兒,而後清理全部內存.
4.分代回收算法
根據對象存貨週期不通,分紅新生代,老年代,在新生代裏面因爲被回收的概率較大因此使用複製算法,在老年代裏面因爲被回收的概率較小使用標記標記整理算法.這樣的組合使用大大的提升了垃圾回收的效率
在HotSpot中GC的時候須要停頓全部執行中的java線程,以保證可達性分析的準確性.
垃圾收集器
是由java虛擬機實現的垃圾算法的實現.
新生代中的垃圾收集器:
Serial收集器 : 使用複製算法,在進行垃圾回收的時候停頓全部java線程.簡單高效.
ParNew收集器 : 複製算法,是Serial收集器多線程的實現. 默認線程數與CPU個數相同.經過 --XX:ParallelGCThreads設置線程大小.
Parallel Scavenge收集器: 和ParNew收集器差很少,可是關注點是達到可控制的吞吐量(用戶代碼運行時間/(用戶代碼運行時間+GC時間)). 經過--XXMaxGCPauseMills設置最大垃圾回收時間. --XX: MaxGcTimeRate設置吞吐量大小.
老年代中的垃圾收集器:
1.Serial Old收集器: 使用標記整理算法.是Serial收集器的老年代版本.
2.Parallet Old收集器:是Parallet Scavenge收集器的老年版本.
3.CMS收集器(Concurrent Mark Sweep) : 使用標記清楚算法,關注點是最短回收時間.適用於互聯網和B/S系統的服務端
垃圾回收過程:
大多數狀況對象在Eden去進行分配,(比較小的狀況如對象比較大的時候會直接放到老年代中),當Eden區沒有足夠的空間的時候,會進行一次Minor GC(把Eden存活對象和非空的Servivor中存活對象複製到空的Servivor空間,而後清除Eden和以前的Servivor空間).每通過一次Minor GC還存活的對象的年齡加一,當年齡達到必定數(默認15)的時候進入老年代.在發生Minor GC以前會檢查一下老年代空閒空間是否足夠,不夠的話進行一次Full GC.