激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - JAVA教程 - JVM如何判斷哪些對象可以回收?

JVM如何判斷哪些對象可以回收?

2021-03-16 00:00大魚仙人大魚 JAVA教程

我們知道在JVM內存中,實例對象基本都是存在于堆中的,那總不能無期限的往里面放吧,一些用不著的對象就需要隨時回收掉,這樣才能保證這個內存的均衡性,才能保證JVM的正常運行。

JVM如何判斷哪些對象可以回收?

前言

我們上一篇分析的是JVM的內存分布,分為堆內存、虛擬機棧、本地方法棧、方法區以及程序計數器等主要區域;各個區域的特點我也就不啰嗦了,想看的給大家直通車:

大魚今天在家本來是閑暇的一天,很舒適,結果這個時候,媽媽敲門進來我房間了,咨詢我有沒有時間幫忙打掃一下父母的房間;(沒有時間

當然我不能這么說了,我是個炒雞孝順的好孩子,當然了,媽媽,當然有時間了啊,now go,我的乖乖,這么亂的屋子,不對啊,平時都是很干凈的啊(內心想逃,后悔,想拒絕

不對啊,媽,為什么房間這么亂啊,這有的東西我也不知道要不要扔掉啊,瞬間難到我了,你們生活中有沒有遇到過類似的煩惱?

或者有沒有遇到糾結一個東西要不要扔掉的時候,那時候你是如何做的呢?

我們知道在JVM內存中,實例對象基本都是存在于堆中的,那總不能無期限的往里面放吧,一些用不著的對象就需要隨時回收掉,這樣才能保證這個內存的均衡性,才能保證JVM的正常運行

那么問題來了,JVM如何知道哪些對象該回收、哪些不該回收,就像剛才大魚不知道爸媽房間哪些東西該收拾、哪些不該收拾一個道理的,其實在JVM中是有兩種解決辦法的,分別是引用計數法和可達性分析法兩種方法,來確定這些對象之中哪些是存活著的、哪些是已經死去的(不可能再被任何途徑使用的對象)

問題明白了,下面就是來解決這個問題了,沖吧,干飯人

引用計數算法

這個其實很簡單了,重點就是計數;給對象添加一個引用計數器,每引用一次,計數器加一;引用失效的時候,計數器減一;當計數器為0 的時候,則認為不可能被再次使用了;

我覺得不需要大魚多解釋了應該,這個應該及其好理解,但是,這種方法存在一個致命的問題:無法解決對象相互循環引用的問題

解釋下這個循環引用問題

一起來看看下面這個例子

public class ReferenceCountingGC { 

 

    public Object instance = null

     

    private byte[] bigSize = new byte[2 * 1024 * 1024]; 

    public static void main(String[] args) { 

        ReferenceCountingGC o1 = new ReferenceCountingGC(); 

        ReferenceCountingGC o2 = new ReferenceCountingGC(); 

        o1.instance = o2; 

        o2.instance = o1; 

        o1 = null

        o2 = null

        //假設在這行發生了GC,o1和o2是否被回收 

        System.gc(); 

    } 

上面例子中o1和o2對象都分別將對方作為自己的屬性注入,這也就是形成了所謂的循環引用;最后o1和o2對象都置為null,也就是棧中不再指向堆中的實例對象地址,但是他們還是會互相引用,所以不會被GC回收

再來看個圖解版,加深理解

剛new的o1和o2對象是這個樣子的:

JVM如何判斷哪些對象可以回收?

分別引用了雙方之后是這樣子的狀態:

JVM如何判斷哪些對象可以回收?

最后置為null變成這個樣子的:

JVM如何判斷哪些對象可以回收?

是的,沒錯,最后就變成了如上圖所示的尷尬境地,對象1和對象2在內部互相引用,永遠失效不了,導致GC通過引用計數法判斷他們的引用計數的時候,永遠無法判斷為0,也就是無法回收咯,不就造成了內存泄漏了嗎

可達性分析法

上面說的引用計數法有缺點,而且這個問題還不小,所以現在使用這種方式來作為判斷對象是否存活標準的比較少,多數使用的是另一種,可達性分析法;

先來解釋下可達性分析法

基本思路就是通過一系列的”GC Roots“的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑就是引用鏈,當一個對象到GC Roots沒有任何的引用鏈可達的時候,則證明這個對象是不可用的

什么意思呢?來個白話文版本的,就是選擇一系列的基準點,這個點能通過引用鏈連接到的對象就被認為是可用的,只要是無法到達的,都被認為是不可用的,這個不可用并不一定代表對象死亡,只代表對象無法觸達,無法再次引用

這就像遞歸定義的關系一樣,如果只定義了遞歸項而不定義初始項的話,關系也就無從成立,無從開始;如果初始項定義漏掉了內容的話,遞推的結果也會隨之而漏掉;

什么是GC Roots

垃圾回收時,JVM會首先找到所有的GC Roots,這個過程叫做枚舉根節點,這個過程需要暫停用戶線程,也就是stop the world;然后再從GC Roots這些根節點向下搜索,可達的對象保留,不可達的便會回收掉

那么,到底什么是GC Roots呢?

GC Roots就是對象,就是JVM確定當前絕對不能回收的對象,只有找到這種對象,后面的搜索才會有意義,不能被回收的對象所依賴的對象也就必然不能回收

GC Roots是一種特殊的對象,是Java程序在運行過程中所必須的對象,而且必須是根對象

哪些對象可以作為GC Roots

基本可以作為GC Roots的對象基本分為兩大類:全局對象和執行上下文;

全局對象

  • 方法區靜態屬性引用的對象:全局對象的一種,Class對象本身很難被回收,回收的條件也是很苛刻,只要Class不被回收,靜態成員不會被回收
  • 方法區常量池引用的對象:全局對象,比如字符串常量池,常量初始化之后不會再次改變

執行上下文對象

  • 方法棧的棧幀本地變量表引用的對象:線程方法執行的時候,會將方法打包成一個棧幀入棧執行,方法里得到的局部變量會存放到本地變量表中,只要方法未執行完,還沒出棧,即本地變量表還會被訪問,GC不應該回收
  • JNI本地方法棧引用的對象:和上面同樣的道理
  • 被同步鎖持有的對象:被synchronized鎖住的對象不可回收,否則鎖就失效了,那鎖就沒意義了

不可達的對象一定會回收嗎?(緩刑階段)

其實被判定為 不可達的對象,也不一定是”非死不可“的,還有一次復活機會,這時是處于緩刑階段,要真正宣告一個對象死亡,至少要經歷再次標記過程(其實就是finalize方法在搞怪)

我們在電視中也是經常見到類似的場景,一個人被判定死刑了,午時已到,立即執行,一般這個時候就會出來一個飛刀,刀下留人,皇上有旨;也有可能是一個飛刀,直接二話不說,噼里啪啦一頓操作,把人救走,是不是很熟悉

沒錯,這個過程就是finalize的內部過程,讓被判定死刑的犯人”重獲新生“

標記的前提是對象在進行可達性分析后發現沒有與GC Roots相連接的引用鏈

第一次標記

篩選的條件是這個對象是否有必要執行finalize()方法;若對象未重寫這個方法或者已被虛擬機調用過,虛擬機則認為沒有必要執行,對象被回收

第二次標記

若這個對象有必要執行finalize方法,則這個對象會被放到一個F-Queue隊列中,并在稍后由虛擬機自動創建的一個低優先級的finalizer線程去執行;

這里的執行指的是虛擬機會觸發這個方法,但是不保證運行完成,這樣做的原因是這個方法執行緩慢,也可能出現死循環,嚴重可能會導致回收系統崩潰

finalize是對象逃脫死亡命運的最后一次機會,稍后GC會對F-Queue中的對象進行二次標記,如果在這里面重新和GC Roots掛上引用關系,則可以逃脫被回收的命運;否則,就肯定GG了

方法區的回收

很多人認為方法區沒有垃圾回收,Java虛擬機規范中也確實說過可以不要求虛擬機在方法區實現垃圾收集,而且在方法區中的垃圾回收的性價比一般比較低,在上面說的堆中進行一次垃圾回收會回收70—95的空間,而永久代中的垃圾回收的效率遠低于此

方法區中的垃圾回收主要是兩部分:廢棄常量和無用的類;廢棄常量的回收和Java堆中的對象類似,不多說了

但是判斷一個類是否是無用的類,則條件比較苛刻,需要滿足三個條件:

  • 該類的所有實例都已經被回收,即Java堆中無該類的任何實例
  • 加載該類的ClassLoader已經被回收
  • 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問到該類的方法

虛擬機規范中說的是滿足上面三個條件,便可以對無用的類進行回收,但是并不是必然回收;是否對類對類進行回收,可以根據虛擬機提供的參數來進行控制

在大量使用反射、動態代理、CGLib等ByteCode框架、動態生成JSP以及OSGI這類頻繁自定義ClassLoader的場景都需要虛擬機具備類的卸載功能,以保證永久代不會溢出

我愛總結

我愛總結之JVM如何判斷哪些對象可以回收,總結很重要,整理思路,記得后續的溫故而知新,GitHub地址在下面,我會把所有原創技術文章放到上面,持續不斷的更新

引用計數法:存在循環引用的致命問題

可達性分析法:以GC Roots作為起點,可以達到的就不可回收,不可達到的暫定認為”死亡“;但是不是非死不可,有通過finalize方法加重新連接引用鏈的方法,讓一個對象重新復活;但是不保證執行完成,這種方法是不靠譜的,也是不建議使用的

好了,以上就是全部內容了,我是小魚仙,你們的學習成長小伙伴

我希望有一天能夠靠寫字養活自己,現在還在磨練,這個時間可能會有很多年,感謝你們做我最初的讀者和傳播者。請大家相信,只要給我一份愛,我終究會還你們一頁情的。

原文地址:https://mp.weixin.qq.com/s/wc81VBW57P9mK5DT7kZjBw

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美高清另类自拍视频在线看 | 人人看人人舔 | 深夜毛片免费看 | 中文字幕精品在线视频 | 色网在线视频 | 国产在线观看91精品 | 久久亚洲精品久久国产一区二区 | 美女又黄又www | 欧美一级特黄a | 视频精品久久 | 亚洲一区成人在线 | 中国一级无毛黄色 | 偷偷操偷偷操 | 久久人添人人爽人人爽人人片av | 黑人日比 | 欧美视频99| av在线久草 | 免费视频www在线观看 | 羞羞答答tv | 91久久久国产精品 | 天海翼无删减av三级在线观看 | 欧美wwwsss9999 | 狼人狠狠干 | av在线看网站 | 午夜精品久久久久久久久久久久久蜜桃 | 夫妻性生活交换 | 深夜福利视频绿巨人视频在线观看 | 草草免费视频 | 国产精品久久久久网站 | 欧美黄成人免费网站大全 | av播放在线 | 久久99精品久久久久久园产越南 | www.91成人| 一区二区三区国产在线 | 久久精品视频在线 | va视频在线 | 在线观看视频毛片 | 亚洲天堂午夜 | 嗯~啊~弄嗯~啊h高潮视频 | 黄色片免费看看 | 精品人成|