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