2 GC
Java垃圾回收機制,GC,ZGC等機制
常見的調優參數
命令 | 說明 |
---|---|
-XX:SurvivorRatio | Eden和Survivor的比值,默認8:1 |
-XX:NewRatio | 老年代的和年輕代內存大小的比例 |
-XX:MaxTenuringThreshold | 對象從年輕代晉升到老年代經過GC次數最大的閾值 |
-XX:+PretenuerSizeThreshold | 新生成的對象可直接變爲老年代的閾值 |
2.1 垃圾回收之標記算法
(1)對象被判定爲垃圾的標準
沒有被其他對象引用的就是"垃圾"
(2)判定對象是否爲垃圾的算法有兩種:引用計數算法
和可達性分析算法
① 引用計數算法:
- 通過判斷對象的引用數量來決定對象是否可以被回收; 每個對象實例都有一個引用計數器,被引用則+1,完成引用-1; 任何引用計數器爲0的對象實例,都可以被當作垃圾收集
- 優點:執行效率高,程序執行受影響較小
- 缺點:無法檢測出循環引用的情況,導致內存泄漏(例如,兩個對象互相引用)
② 可達性分析算法:
- 通過判斷對象的引用鏈是否可達來決定對象是否可以被回收; 可以想象這個程序中所有的引用都是從一個
GC Root
出發,鏈接起來的引用圖,如果在圖中,說明對象還在被引用,如果沒有被引用則可以判定爲垃圾 - 可以作爲
GC Root
的對象: - 虛擬機棧中引用的對象(棧幀中的本地變量表)
- 方法區中的常量引用對象
- 方法區中的類靜態屬性引用對象
- 本地方法棧中JNI(Native方法)的引用對象
- 活躍線程的引用對象
2.2 談談你瞭解的垃圾回收算法
(1) 標記-清除算法(Mark and Sweep)
標記
:從根集合進行掃描,對存活的對象進行標記;清除
:對堆內存從頭到尾進行線性遍歷,回收不可達對象內存- 產生的後果:容易導致內存
碎片化
(2)複製算法(Copying)
- 將一塊可用的內存按比例或者容量分爲
對象面
和空閒面
,對象在對象面上創建,存活的對象被從對象面複製到空閒面,將對象面所有內存清除 - 優點:解決碎片化問題,順序分配內存,簡單高效,適用於對象存活率低的場景(尤其適用於
年輕代
中)
(3)標記-整理算法(Compacting)
標記
:從根集合進行掃描,對存活的對象進行標記;清除
:移動所有存活的對象,且按照內存地址依次排列,然後將末端內存地址以後的內存全部回收.- 優點:解決了
標記-清除算法
中產生的碎片化問題,避免了內存的不連續;不用設置兩塊內存互換;適用於存活率高的場景(如老年代
中) - 缺點:成本更高;
(4)分代收集算法(Generational Collector)
- 可以理解爲是垃圾回收算法的組合拳; 其按照對象生命週期的不同劃分在不同堆中,對不同的堆採用不同的垃圾回收算法
- 目的: 爲了提高JVM垃圾回收效率
- 分帶收集算法中GC的分類:
MinorGC
,Full GC
2.3 分代收集算法的應用
(1)在年輕代中使用複製算法
年輕代:存放那些生命週期短的對象,其分爲Eden區和兩個Survivor區(分別叫做from,to),這三個區的大小比例爲8:1:1.
創建新的對象是在Eden區中,在進行GC時,使用複製算法
將Eden中存活對象和from區中存活對象複製到to區中,年齡+1,清空Eden區和from區.此時,from區變爲了to區,to區變爲from區,下一次觸發GC時,依舊是使用複製算法
將Eden中存活對象和from區中存活對象複製到to區中,年齡+1,清空Eden區和from區.
當某個存活對象的年齡達到某個值(比如15時,其可以通過-XX:MaxTenuringThreshold
設置),就會被移動到老年代中.
(2)對象如何晉升到老年代
- ①首先在經歷一定的Minor次數依舊存活的對象(也就是年齡達到要求的)
- ②Survivor區中存放不下的對象
- ③新生成的大對象(
-XX:+PretenuerSizeThreshold
)
(3)在老年代中使用標記-清除算法
和標記-整理算法
老年代:存放生命週期較長的對象