一、判斷對象是否消亡的算法
1、引用計數算法 —— 因為無法解決對象直接相互引用的問題,因此主流的java虛擬機沒有選用此方法
基本思想:為每一個對象添加一個引用計數器,每當有一個地方引用這個對象時,計數器值加1,當引用失效時,計數器值減1;任何時刻計數器的值為0的對象都是可被回收對象。
2、可達性分析法
基本思想:將一系列被稱為GC Roots的變量作為初始的存活對象集合,然后從該集合出發,所有能被該集合引用到的對象,將其加入到集合中,不能被該集合引用到的對象,則宣告它們死亡。
GC Roots : 是一些由堆外指向堆內的引用
一般而言GC Roots包括但不限於以下幾種:
Java 方法棧楨中的局部變量;
已加載類的靜態變量;
JNI handles;
已啟動且未停止的 Java 線程
二、堆內存分布
1、新生代:
新生代按照8:1:1的比例分為Eden(伊甸區)和兩個幸存區Survivor(from和to)
2、老年代
三、GC算法
1、標記清除:
標記清除是最早開發出來的算法。從根開始將可能被引用的對象用遞歸的方式進行標記,然后將沒有被標記的對象作為垃圾進行回收
2、標記整理:
標記整理又稱為標記壓縮,是標記清除的變種。因為標記清除會造成很多內存碎片,標記整理就是將標記清除后的內存進行碎片整理
3、復制收集
將可用內存按容量划分為大小相等的兩塊區域,每次只使用其中一塊,當這一塊內存用完后,將該內存中所有存活的對象復制到另外一塊內存上,然后把已使用過的內存一次性清理掉。
四、對象分配原則
1、新創建的對象優先分配到Eden區,如果Eden空間不足時,虛擬機執行一次Minor GC
2、大對象直接進入老年代——大對象是指需要大量連續內存空間的對象。這樣做的目的是為了避免Eden區和兩個Survivor區發生大量的內存拷貝
3、長期存活的對象進入老年代——虛擬機為每一個對象定義了一個年齡計數器,如果經歷了一次Minor GC對象會進入Survivor區,之后每經歷一次Minor GC,對象年齡加1,直到達到年齡閥值進入老年代
4、動態判斷對象的年齡——如果Survivor區相同年齡的所有對象的內存大小總和大於Survivor內存空間的一半,則大於或等於該年齡的對象進入老年代
5、空間分配擔保——每次進行Minor GC時,JVM會計算Survivor區進入老年代對象的內存大小,如果這個值大於老年代剩余內存空間大小,則進行一次Full GC;如果小於,則檢查HandlePromotionFailure設置,如果true,則只進行Minor GC,如果false,則進行Full GC
五、GC策略
新生代可用策略
1、Serial Copying——串行GC
2、ParNew——並行GC
3、Parallel Scavenge——並行回收GC
老年代可用策略
1、Serial MSC——串行GC
2、Parallel MSC——並行GC
3、CMS——並發GC
G1收集器——引入分區的思路,弱化了分代的概念
GC策略+GC算法實現GC功能
六、GC流程
1、新創建的對象進入新生代Eden區,Eden區判斷內存是否滿了,如果滿了,則執行Minor GC,將Eden區和Survivor from區存活的對象復制到 Survivor to區,清除Eden區和Survivor from區
2、在執行Minor GC后,Survivor to區中,對象年齡達到閥值對象移動到老年代,如果老年代剩余的內存空間小於Survivor to區移動過來的對象大小,則觸發Full GC
3、如果觸發Full GC后內存仍然不足,則拋出OutOfMemeryError異常