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