一、GC要做的事
1、哪些內存需要回收,2、什么時候回收,3、怎么回收
二、如何確定內存垃圾
1、引用計數法:通過判斷對象的引用數量來決定對象是否可以被回收,任何引用計數為0的對象實例可以被當做垃圾收集
優:執行效率高,程序執行受影響小
缺:無法檢測出循環引用的情況,導致內存泄漏。eg:父對子有一個引用,子對父也有一個引用,所以兩個對象引用用不為0
2、可達性分析:判斷對象的引用鏈是否可達來決定對象是否可以被回收,通過GC Root到各對象是否可達來判斷
可作為GC Root的對象:虛擬機棧中引用的對象(棧幀中的本地變量表),方法區中的常量引用的對象,方法區中的類靜態屬性引用的對象,本地方法棧中JNI(Native)的引用對象,活躍線程的引用對象。
三、垃圾回收算法
1、標記-清除算法:可達性分析
標記:從根集合進行掃描,對存活的對象進行標記,清除:對堆內存從頭到尾進行線性遍歷,回收不可達對象內存
2、復制算法:(新生代)
分為對象面和空閑面,對象在對象面上創建,存活的對象被從對象面復制到空閑面,將對象面所有對象內存清除。對象存活率低(新生代)
解決了碎片化問題,新生代中,對象存活率低,所以要復制的對象很少,此方法順序分配內存,簡單高效。存活率較高時就會力不從心
3、標記-整理算法:(老年代)
標記:從根集合進行掃描,對存活的對象進行標記,清除:移動所有存活的對象,且按照內存地址次序依次排列,然后將末端內存地址以后的內存全部回收。在標記-清除算法的基礎上,添加了移動的功能
4、分代手機算法:
按照對象生命周期的不同划分區域以采用不同的垃圾回收算法,提高jvm垃圾回收效率
GC 的分類:
(1/3堆內存空間)Minor GC:所有新生成的對象一般都在新生代
Eden(伊甸園), 80%,兩個Survivor區(from,to),10%
Eden中存儲對象,當達到閾值后(Minor次數),會向任意一個Survivor區中存儲Eden中當前還存活的對象,清除Eden中所有對象,且年齡+1,此時當前區就成了from區,當下一次Eden又達到閾值,且當前Survivor區也達到了閾值,此時會向另外一個Survivor區存儲,年齡+1,另外一Survivor區就會變成from區。
對象如何晉升到老年代:
1、經歷一定Minor次數(默認15)依然存活的對象,2、Survivor區中存放不下的對象,3、新生成的大對象。
(2/3堆內存空間)Full GC:存放生命周期較長的對象
標記-清除算法,標記-整理算法
Full GC 和Major GC,Full GC 比Minor GC 回收效率慢,但執行頻率低。
觸發Full GC 的條件
老年代空間不足,永久代空間不足
四、垃圾收集器
CMS和Parallel Scavenge收集器不能共存,因為,Parallel Scavenge和G1使用的都是類似於框架,不能與CMS更好的共存
新生代垃圾收集器:
1、Serial收集器(-XX:+UseSerialGC,復制算法)
單線程收集,進行垃圾收集時,必須暫停所有工作線程
簡單高效,Client模式下的年輕代收集器
2、ParNew收集器(-XX:+UseParNewGC,復制算法)
多線程收集,其余的行為、特點和Serial收集器一樣
單核執行效率不如Serial(由於線程切換需要開銷),多核下執行才有優勢
3、Parallel Scavenge收集器(-XX:+UseParallelGC,復制算法)
吞吐量= 運行代碼時間/(運行代碼時間+垃圾回收處理時間)
比起之前兩個關注用戶線程停頓時間,更關注系統的吞吐量
多線程下執行才有優勢,Server模式下的年輕代收集器
老年代垃圾收集器:
1、Serial Old收集器(-XX:+UseSerialOlaGC,標記-整理算法)
單線程收集,進行垃圾收集時,必須暫停所有工作線程
簡單高效,Client模式下的年輕代收集器
2、Parallel Old收集器(-XX:+UseParallelOldGC,標記-整理算法)
多線程,吞吐量優先
3、CMS收集器(-XX:+UseConcMarkSweepGC,標記-清除算法)
G1和CMS的回收機制
G1同時回收老年代和年輕代,而CMS只能回收老年代,需要配合一個年輕代收集器。另外G1的分代更多是邏輯上的概念,G1將內存分成多個等大小的region,Eden/ Survivor/Old分別是一部分region的邏輯集合,物理上內存地址並不連續。