摘要:但是為了豐富引用的種類,以適應各種應用,中加入了中引用,但是除了強引用,其生命周期會有所不同,生存能力遞減。加載該類的已被回收。
GC面臨的問題有三個:哪些內(nèi)存需要回收、什么時候回收和怎么回收
哪些內(nèi)存需要回收,一般有兩種方法
引用計數(shù)
對每個對象都有個被引用的次數(shù),單被引用的次數(shù)為0的時候,就表示對象需要被回收
引用計數(shù)的缺點是沒有辦法解決循環(huán)引用導致的內(nèi)存泄露問題
可達性分析
現(xiàn)在主流的GC方法都使用可達性分析
以GC root為起點,遍歷整個樹(或者圖),如果沒有到達過某個對象,則表示這個對象需要被回收
GC Root表示引用鏈的起點,包括函數(shù)調(diào)用棧中引用的對象、static靜態(tài)變量和常量的引用對象、方法區(qū)中常量引用的對象,本地方法棧中JNI引用的對象
也可以分為棧中的對象、永久代的對象、本地方法棧中JNI引用的對象
object什么時候會被回收
一般而言,只要沒有引用指向object,就可以在gc的時候被回收(老年代需要在Full GC,永久代需要在設定的幾次Full FC)。但是為了豐富引用的種類,以適應各種應用,JDK1.2中加入了4中引用,但是除了強引用,其生命周期會有所不同,生存能力遞減。
強引用(Strong Reference)
即普通引用
軟引用(Soft Reference)
當觸發(fā)OutOfMemoryException之前,會觸發(fā)第二次GC,回收這些Object
弱引用(Weak Reference)
當觸發(fā)GC的時候,回收這些Object
虛引用(Phantom Reference)
對Object的生存無意義,當Object被回收時,會觸發(fā)虛引用的通知
對已object在被回收的時候,還會有一個特例,就是定制Object的finalize方法,使之重新與GC Root關聯(lián),可以使Object逃脫回收
finalize方法在object被GC的時候會被執(zhí)行
但是下次被GC的時候,不會再次執(zhí)行finalize方法(finalize方法在生命周期內(nèi)只會執(zhí)行一次),所以不會再次逃脫回收
方法區(qū)或者Hotspot的永久代也會進行GC
普通常量池常量只要沒有引用指向它,就可以被回收
類的回收判定需要滿足3個條件
堆中不存在該類實例,即沒有指向該類的引用(按照jvm的內(nèi)存布局,類實例是會有指向類信息的pointer或者handler的。
加載該類的class loader已被回收。(class loader應該存在操縱其加載的類的方法,即還存在某種聯(lián)系)
該類對應的java.lang.Class對象沒有在任何地方被引用,在任何地方無法通過反射訪問該類的方法(如果存在這種引用,則可以通過反射的機制,進行訪問該類,這會導致錯誤,有點像race condition,持有緩存,內(nèi)容卻被改變了)
由這3個條件應該可以推論出:類實例、class loader、對應的java.lang.Class類和類信息都存在某種聯(lián)系,使得可以通過這些東西操縱或者訪問類信息。
對于內(nèi)存怎么回收的問題,內(nèi)存的回收算法一般分為三種
標記-清除
先對需要進行回收的內(nèi)存進行標記,然后在進行清除
復制算法
將內(nèi)存分為相等的兩塊,每次只使用其中一塊,當當前使用的內(nèi)存塊使用完了之后,將存活的對象復制到另一內(nèi)存塊
Hotspot將新生代分為一個Eden和兩個Survivor區(qū),默認比例為8:1:1
minor gc的時候,將eden去和當前survivor區(qū)的存活對象復制到另一塊survivor區(qū)
如果survivor區(qū)不足以放置存活的object,使用分配擔保機制,部分object將直接進入老年代
標記-整理
先對存活的object進行標記,然后將object進行整理(統(tǒng)一往一端移動),最后將剩余的內(nèi)存進行回收
分代收集
就是將內(nèi)存分為不同的區(qū)域,一般分為新生代和老年代兩部分,然后在不同的部分應用不同的收集算法
一般來說新生代使用復制算法,因為一般只會有少量object存活
老年代使用標記-清除或者標記-整理算法,因為對象存活率高,沒有另外的內(nèi)存進行分配擔保
Hostspot的算法實現(xiàn)
枚舉根節(jié)點
為了避免race condition的問題,這里需要進行stop the world的操作,保證一致性
為了提高標記的效率,降低stop the world的時間,商業(yè)vm一般都會使用準確式GC,會使用一些方法記錄下引用的準確位置,避免全局內(nèi)存掃描
Hostspot使用的是OopMap的數(shù)據(jù)結構來達到這個目的
OopMap的具體使用方法還需要深入了解
安全點
由于能導致OopMap變化的指令非常多,所以Hostspot設置安全點,只有在安全點才會生成OopMap,這也導致只有在安全點才能停頓下來進行GC
如何使所有線程進入安全點的方法有兩個
搶先式中斷,基本上不用
先把所有線程中斷,如果線程不在安全點,則恢復線程讓它到達安全點
主動式中斷
設置標記位,標記是否正在進行根節(jié)點枚舉
在安全點輪詢標記位
安全區(qū)域
如果線程不運行,如sleep或者blocked狀態(tài),安全點就沒法解決問題
安全區(qū)域指在這個區(qū)域內(nèi),代碼引用關系不會變化
當線程到達安全區(qū)域時,會對自己進行標記,GC時,就不需要管安全狀態(tài)的線程
當線程需要離開安全區(qū)域,需要檢查根節(jié)點枚舉標記位
垃圾收集器
Serial收集器
簡單粗暴的串行收集器
適合內(nèi)存不大,單CPU(可以避免線程交互開銷),對stop the world不太敏感的client環(huán)境
ParNew收集器
Parallel New Generation,新生代并行收集器
Parallel Scavenge收集器
為控制吞吐量而生
通過控制stop the world的最大時間和gc時間的最大比例來控制gc時間,控制吞吐量
也可以使用自適應參數(shù)
算法主要控制stop the world的時間,但是代價是更頻繁的gc和總體更長的gc時間總和
Serial Old收集器
老年代的串行收集器
使用的是標記-整體算法
Parallel Old收集器
老年代的并行收集器
和Parallel Scavenge收集器一起使用,應用于注重吞吐量和CPU敏感的場合
CMS收集器
Concurrent Mark Sweep,Mark Sweep,基于標記-清除算法
分為初始標記、并行標記、重新標記、并發(fā)清除4個階段
其中初始標記和重新標記 都會stop the world
耗時最長的并發(fā)標記和并發(fā)清除都可以和用戶線程一起運行
缺點
并CPU資源非常敏感,并發(fā)情況下,占用部分CPU資源,會導致吞吐量下降
無法處理浮動垃圾,可能出現(xiàn)“concurrent mode failed”而導致另一次Full GC
浮動垃圾,在并發(fā)清理階段出現(xiàn)的垃圾,沒法當次GC清除
需要預留老年代空間,給GC時,用戶程序使用
標記-清除算法會導致內(nèi)存碎片
可以設置是否在Full GC時整理內(nèi)存,多少次Full GC整理一次內(nèi)存
G1收集器
Garbage First
優(yōu)點有:
并行與并發(fā)
分代手機
空間整合
整體來看是標記-整理算法,局部來看是標記-復制算法
可預測的停頓
通過設置GC時間的不得超過一定比例,幾乎是實時Java(RTSJ)垃圾收集器的特征
G1實現(xiàn)
G1將內(nèi)存分為多個相等的區(qū)域
老年代、新生代的概念還存在,但是改為了內(nèi)存區(qū)域的集合,而不是固定的區(qū)域
G1跟蹤各個Region區(qū)域里面垃圾堆積的價值(即花費時間回收內(nèi)存的性價比),維護優(yōu)先列表
由優(yōu)先列表建立回收時間預測模型,優(yōu)先收集性價比高的垃圾
由于分區(qū)域回收內(nèi)存,G1的區(qū)域之間相互引用,導致可達性分析耗時的問題相比之前的收集器顯得更加突出了
通過remember set來避免全堆掃描
remember set記錄被其它區(qū)域引用的情況(待補充)
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/65561.html
摘要:堆和方法區(qū)只有在程序運行時才能確定內(nèi)存的使用情況,垃圾回收器所關注的主要就是這部分內(nèi)存。虛擬機會根據(jù)當前系統(tǒng)的運行情況收集性能監(jiān)控信息,動態(tài)調(diào)整比率參數(shù)以提供最合適的停頓時間或最大的吞吐量。 Tip:內(nèi)容為對《深入理解Java虛擬機》(周志明 著)第三章內(nèi)容的總結和筆記。這是第一次拜讀時讀到的一些重點,做個分享,也為后面再次閱讀和實踐做保障。 3.1 概述 程序計數(shù)器、虛擬機棧、本地...
摘要:抽時間重新讀了一遍深入理解一書。驗證確保文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全??梢娦钥梢娦允侵府斠粋€線程修改了共享變量的值,其他線程能夠立即得知這個修改。 抽時間重新讀了一遍《深入理解JVM》一書。以下為摘錄內(nèi)容。 1 java內(nèi)存區(qū)域 showImg(https://segmentfault.com/img/bVboDgk?w=617&h=365...
摘要:前言本文內(nèi)容基本摘抄自深入理解虛擬機,以供復習之用,沒有多少參考價值。此區(qū)域是唯一一個在虛擬機規(guī)范中沒有規(guī)定任何情況的區(qū)域。堆是所有線程共享的內(nèi)存區(qū)域,在虛擬機啟動時創(chuàng)建。虛擬機上把方法區(qū)稱為永久代。 前言 本文內(nèi)容基本摘抄自《深入理解Java虛擬機》,以供復習之用,沒有多少參考價值。想要更詳細了解請參考原書。 第二章 1.運行時數(shù)據(jù)區(qū)域 showImg(https://segment...
摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡介領域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號作者架構師奮斗者掃描主頁左側二維碼,加入群聊,一起學習一起進步歡迎點贊收藏留言前情提要無意間聽到領導們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨立帶隊的人太少,簡而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...
摘要:執(zhí)行引擎作用執(zhí)行字節(jié)碼,或者執(zhí)行本地方法運行時數(shù)據(jù)區(qū)其實就是指在運行期間,其對內(nèi)存空間的劃分和分配。 雖是讀書筆記,但是如轉(zhuǎn)載請注明出處https://uestc-dpz.github.io..拒絕伸手復制黨 JVM Java 虛擬機 Java 虛擬機(Java virtual machine,JVM)是運行 Java 程序必不可少的機制。JVM實現(xiàn)了Java語言最重要的特征:即平臺...
閱讀 1453·2021-09-28 09:43
閱讀 4348·2021-09-04 16:41
閱讀 1980·2019-08-30 15:44
閱讀 3875·2019-08-30 15:43
閱讀 832·2019-08-30 14:21
閱讀 2084·2019-08-30 11:00
閱讀 3378·2019-08-29 16:20
閱讀 2005·2019-08-29 14:21