垃圾回收
垃圾回收
在垃圾回收中,我們需要判斷三個條件,什么時候回收?在哪里回收?以及如何回收
1:hotspot的GC分類
- partial GC,并不收集整個GC堆的模式
- young GC,只收集年輕代的GC
- old GC,只收集老年代的GC,只有CMS中的concurrent collection是這個模式
- mixed GC,收集整個年輕代以及部分老年代的GC,只有G1是這個模式
- full GC,收集整個堆
- 包括young,old,永久代(如果存在的話)
- major GC,通常和full GC 是等價的,收集整個GC堆,有人說 major GC的時候,一定要問一下是上面的ull GC,還是 old GC
2:判斷對象死亡
- 引用計數法
- 給一個對象加上一個引用計數器,每次引用數字加一,引用失效數字減一
- 計數器為0 的時候,對象不可能被使用
- 循環依賴的問題
- 引用的類型
- 強引用
- 生活中的必備品
- 只有強引用是包內可見的,其他的都是public
- 普通創建的對象默認都是強引用的,在JVM中,即使拋出OOM,強引用也不會被回收
- 弱引用
- 可有可無的商品
- 內存敏感的高速緩存
- 在內存不夠的時候,他會為了避免拋出OOM,而回收掉弱引用
- 軟引用
- 在任何時間都可能會被清除掉
- 只要一旦被 GC看到,就會被清除
- 虛引用
- 形同虛設
- 跟蹤對象被垃圾回收的活動
- 強引用
- 可達性質分析
- 從GCroots開始,從該點開始向下搜索,走過的稱為引用鏈。如果一個對象沒有在引用戀上,說明是不可達的
- 虛擬機棧中的引用的對象
- 本地方法棧(native)中引用的對象
- 本地區中類靜態屬性引用的對象
- 本地區中常量引用的對象
- 所有被同步鎖持有的對象
- 不可達的并非非死不可
- 不可達的對象,可以看作是死緩
- 此對象是否有必要執行inalize方法,
- 當對象沒有覆蓋finalize的時候
- finalize 已經被虛擬機調用的時候
- finalize方法
- finalize 是object的方法,當垃圾回收回收掉對象之前,就會調用這個的方法,處理最后的后事
- 如果它覆蓋了finalize方法,并且在調用的時候,引用到了GC roots鏈上,此時就活了
- finalize 只能調用一次,
- finalize 是object的方法,當垃圾回收回收掉對象之前,就會調用這個的方法,處理最后的后事
- 從GCroots開始,從該點開始向下搜索,走過的稱為引用鏈。如果一個對象沒有在引用戀上,說明是不可達的
3:常量是廢棄常量?
- 運行時常量池主要存放的是常量,那么,我們如何判斷一個常量是不是廢棄常量呢?
- JDK 1.7之前,常量池放在方法區,因此對方法區的實現是永久代
- JDK1.7,字符串常量池被拿到了堆中,而其他的常量池還在方法區,也就是永久代
- 1.8,移除了永久代用元空間來取而代之,運行時的字符串常量池還在堆中,運行時常量池還在方法區,只不過方法區由永久代變成了元空間
- 假設字符串常量池中有“”abc“,如果當前沒有任何的string對象引用該對象的話,那么說明就是廢棄對象。
4:類是一個無用的類?
- 該類的所有實例已經回收,即在堆中不存在任何的類對象
- 加載該類的classLoader已經被回收
- 該類的java.lang.Class沒有在任何對象引用過,無法在任何對方通過反射訪問該類的方法
- 在滿足上面三個條件之后,JVM可以對該類進行回收,但是也并不絕對。
5:垃圾回收算法
- 標記清除
- 標記出所有不需要回收的對象
- 清除掉所有沒有標記的對象
- 簡單
- 存在內碎片
- 標記整理
- 標記出所有不需要回收的算法
- 讓存活者的進行移動,使得不存在內存碎片
- 清除掉剩余的空間即可
- 復制
- 內存分為兩塊
- 每次使用其中的一塊,當這一塊使用完之后,就將活著的對象復制到另外一邊去
- 再把這邊的對象整體清除掉
- 效率高
- 浪費空間
- 分代回收
- 根據對象的年齡,來綜合的使用上述各種垃圾回收方法
- 在新生代,死亡的概率是很高的,選擇復制算法,每次復制少量的對象,并且效率高
- 在老年代,成活的效率比較高,使用標記清除,或者是標記整理的算法進行收集
- 過程
- 新生代和老年代,大概約為1:2
- 新生代中又分為伊甸區,from survivor,to survivor,默認是8:1:1
- 新生的對象都是在伊甸區,每次清除的時候會將伊甸區和 from survivor 中存活的對象移動到 to survivor中
- 清除 伊甸區和 from survivor,再把 to survivor中的對象移動到from survivor
- 老生代當達到某個數值的時候就會出發全局的垃圾回收
- 年齡
- 每次from survivor 和 to survivor之間的互相移動,年齡加一
- 當年齡達到15的時候,就移動到老年區,因為在mark word 中年齡是 4位
- 大對象直接在老年區
6:垃圾收集器
-
serial(串行) 收集器
- 使用一條線程進行垃圾收集工作
- 進行垃圾回收的時候會暫停其他的線程(stop the world)
- 優點
- 簡單,高效
- 由于沒有線程的交互開銷,可以獲得很高的單線程收集效率
- 運行在client 模式下的虛擬機是一個很不錯的選擇
- 優點
-
parnew 收集器
- 就是串行收集器的 多線程版本,和serial一模一樣
- 新生代采用標記——復制算法,而老年代采用標記,清除算法
- 運行在server端的首要選擇
- 只有serial,和parnew配合工作
-
parallel scavenge 收集器
- 關注的是吞吐量,高效率的使用CPU
- 新生代采用標記復制算法,老年代采用標記整理算法
-
CMS 收集器
- 獲取最短回收停頓時間為目標的收集器,符合在用戶體驗的使用
- 第一款的并發收集器,實現了垃圾回收和用戶線程同時工作
- 初始標記:暫停所有的線程,記錄下和GC roots 相連的對象
- 并發標記:開啟GC 和用戶線程,用一個閉包的結構去記錄可達對象,
- 重新標記:修正在并發標記階段因為用戶程序運行導致的變動標記記錄
- 并發清除:開啟用戶線程,同時GC線程開始對未標記的區域做清掃
- 優點
- 并發標記 停頓小
- 缺點
- 對CPU 資源敏感
- 無法處理浮動的額垃圾
- 標記清除,導致有大量的內存碎片
-
G1 收集器
- 面向服務器的垃圾回收器,針對多核處理器和大內存的機器
- 并發和并行:G1能夠充分的利用CPU,多核,大內存的硬件優勢
- 分代收集:也采用了分代回收的機制
- 空間整合:G1從整體上來看是使用標記整理,從局部上是標記復制
- 可以預測的停頓:能偶建立可預測的停頓時間模型,
- 過程
- 初始標記
- 并發標記
- 最終標記
- 篩選回歸
- 維護了一個優先隊列,每次根據收集時間,以此選擇價值最大的垃圾
- garage First,保證了在有限的時間內能夠獲得最大價值的垃圾回收
- 過程
-
ZGC 收集器
- stop the world 的情況會更少
2021.3.12.12:09
總結
- 上一篇: python中文件位置的书写
- 下一篇: 并发的容器