JVM系列二:垃圾回收
什么時候回收對象
引用計數法?
1、原理:為對象添加一個引用計數器,當對象增加一個引用時計數器加 1,引用失效時計數器減 1。引用計數為 0 的對象可被回收。
2、缺點:無法解決循環引用問題
可達性分析
1、原理:以 GC Roots 為起始點進行搜索,可達的對象都是存活的,不可達的對象可被回收。
2、可作為GC Root的對象:
- 虛擬機棧中局部變量表中引用的對象
- 本地方法棧中 JNI 中引用的對象
- 方法區中類靜態屬性引用的對象
- 方法區中的常量引用的對象
方法區回收
1、主要是對類的卸載和對常量池的回收,對于大量引用動態代理和反射的場景下,類的卸載是具有重要意義的
2、類的卸載需滿足以下三個條件,但是就算三個條件都滿足也不一定就被卸載
- 該類所有的實例都已經被回收,此時堆中不存在該類的任何實例。
- 加載該類的 ClassLoader 已經被回收。
- 該類對應的 Class 對象沒有在任何地方被引用,也就無法在任何地方通過反射訪問該類方法。
finalize方法
1、類似 C++ 的析構函數,用于關閉外部資源。但是 try-finally 等方式可以做得更好,并且該方法運行代價很高,不確定性大,無法保證各個對象的調用順序,因此最好不要使用。
2、當一個對象可被回收時,如果需要執行該對象的 finalize() 方法,那么就有可能在該方法中讓對象重新被引用,從而實現自救。
自救只能進行一次,如果回收的對象之前調用了 finalize() 方法自救,后面回收時不會再調用該方法
四種引用
不管是引用計數法還是可達性分析,引用的判斷與計數都是很重要的
強引用
1、特點:不會被回收
2、構造方式:new
?1?Object object = new Object();?
軟應用
1、特點:只有在內存不夠的時候才會被回收
2、構造方式:SoftReference
1 Object object = new Object(); 2 SoftReference<Object> sf = new SoftReference<Object>(object); 3 object = null;//使對象只能被軟引用關聯?
弱引用
1、特點:下一次內存回收的時候一定會被回收
2、構造方式:WeakReference
1 Object object = new Object(); 2 WeakReference<Object> sf = new WeakReference<Object>(object); 3 object = null;?
虛引用
1、特點:沒有辦法得到一個虛引用對象,設置它的唯一目的就是在系統回收它的時候得到一個通知
2、構造方式:PhantomReference
1 Object object = new Object(); 2 PhantomReference<Object> sf = new PhantomReference<Object>(object); 3 object = null;?
垃圾收集算法
標記-清除算法
1、過程
(1)標記階段:程序會檢查每個對象是否為活動對象,如果是活動對象,則程序會在對象頭部打上標記。
(2)清除階段:會進行對象回收并取消標志位,另外,還會判斷回收后的分塊與前一個空閑分塊是否連續,若連續,會合并這兩個分塊。
回收對象就是把對象作為分塊,連接到被稱為 “空閑鏈表” 的單向鏈表,之后進行分配時只需要遍歷這個空閑鏈表,就可以找到分塊。
在分配時,程序會搜索空閑鏈表尋找空間大于等于新對象大小 size 的塊 block。如果它找到的塊等于 size,會直接返回這個分塊;
如果找到的塊大于 size,會將塊分割成大小為 size 與 (block - size) 的兩部分,返回大小為 size 的分塊,并把大小為 (block - size) 的塊返回給空閑鏈表。
2、圖解
?
?
3、缺點
- 標記和清除的過程效率都不高
- 可能產生大量內存碎片
?
標記-整理算法
1、過程
讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存。
2、圖解
?
?
3、缺點
每次都要移動存活的對象
?
復制算法
1、過程
將內存劃分為大小相等的兩塊,每次只使用其中一塊,當這一塊內存用完了就將還存活的對象復制到另一塊上面,然后再把使用過的內存空間進行一次清理。
現在的商業虛擬機都采用這種收集算法回收新生代,但是并不是劃分為大小相等的兩塊,而是一塊較大的 Eden 空間和兩塊較小的 Survivor 空間,每次使用 Eden 和其中一塊 Survivor。在回收時,將 Eden 和 Survivor 中還存活著的對象全部復制到另一塊 Survivor 上,最后清理 Eden 和使用過的那一塊 Survivor。
HotSpot 虛擬機的 Eden 和 Survivor 大小比例默認為 8:1,保證了內存的利用率達到 90%。如果每次回收有多于 10% 的對象存活,那么一塊 Survivor 就不夠用了,此時需要依賴于老年代進行空間分配擔保,也就是借用老年代的空間存儲放不下的對象。
2、圖解
?
3、缺點
每次只能用到局部的內存
?
分代收集算法
1、按照對象生存周期將內存分為不同的區域主要分成新生代和老年代,不同的區域采取不同的收集算法
2、新生代:采取復制算法
? 老年代:采取標記-清理算法或者標記-整理算法
?
垃圾收集器
?
新生代收集器
Serial收集器
?
ParNew收集器
?
Parallel Scavenge收集器
?
與 ParNew 一樣是多線程收集器。
其它收集器目標是盡可能縮短垃圾收集時用戶線程的停頓時間,而它的目標是達到一個可控制的吞吐量,因此它被稱為“吞吐量優先”收集器。這里的吞吐量指 CPU 用于運行用戶程序的時間占總時間的比值。
?
老年代收集器
?
Serial Old收集器
?
Parallel Old收集器
?
CMS收集器
?
G1收集器
?
?
搭配關系
?
比較總結
?
| 收集器 | 收集算法 | 新生代/老年代 | 備注 |
| Serial | 復制算法 | 新生代 | |
| ParNew | 復制算法 | 新生代 | |
| Parallel Scavenge | 復制算法 | 新生代 | ? |
| Serial Old | 標記-整理算法 | 老年代 | ? |
| Parallel Old | 標記-整理算法 | 老年代 | |
| CMS | 標記-清除算法 | 老年代 | ? |
| G1 | 標記-整理算法 | 新生代+老年代 | ? |
轉載于:https://www.cnblogs.com/huanglf714/p/11027336.html
總結
以上是生活随笔為你收集整理的JVM系列二:垃圾回收的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019春季学期进度报告(十六)
- 下一篇: oracle之4多行函数之分组函数