溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

跟面試官聊到JVM,他99%會(huì)讓你談?wù)勥@個(gè)問題!

發(fā)布時(shí)間:2020-08-10 05:11:27 來(lái)源:ITPUB博客 閱讀:148 作者:JAVA架構(gòu) 欄目:軟件技術(shù)

但凡問到 JVM(Java 虛擬機(jī))通常有 99% 的概率一定會(huì)問: 在 JVM 中如何判斷一個(gè)對(duì)象的生死狀態(tài)?

本文就來(lái)聊聊這個(gè)問題,判斷對(duì)象的生死狀態(tài)的算法有以下幾個(gè):

1、引用計(jì)數(shù)器算法

引用計(jì)算器判斷對(duì)象是否存活的算法是這樣的:給每一個(gè)對(duì)象設(shè)置一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用這個(gè)對(duì)象的時(shí)候,計(jì)數(shù)器就加1,與之相反,每當(dāng)引用失效的時(shí)候就減1。

優(yōu)點(diǎn) :實(shí)現(xiàn)簡(jiǎn)單、性能高。

缺點(diǎn) :增減處理頻繁消耗cpu計(jì)算、計(jì)數(shù)器占用很多位浪費(fèi)空間、最重要的缺點(diǎn)是無(wú)法解決循環(huán)引用的問題。

因?yàn)橐糜?jì)數(shù)器算法很難解決循環(huán)引用的問題,所以主流的Java虛擬機(jī)都沒有使用引用計(jì)數(shù)器算法來(lái)管理內(nèi)存。

運(yùn)行的結(jié)果:

開始:117 M

運(yùn)行中:96 M

結(jié)束:119 M

從結(jié)果可以看出,虛擬機(jī)并沒有因?yàn)橄嗷ヒ镁筒换厥账鼈?,也?cè)面說明了虛擬機(jī)并不是使用引用計(jì)數(shù)器實(shí)現(xiàn)的。

2、可達(dá)性分析算法

在主流的語(yǔ)言的主流實(shí)現(xiàn)中,比如Java、C#、甚至是古老的Lisp都是使用的可達(dá)性分析算法來(lái)判斷對(duì)象是否存活的。

這個(gè)算法的核心思路就是通過一些列的“GC Roots”對(duì)象作為起始點(diǎn),從這些對(duì)象開始往下搜索,搜索所經(jīng)過的路徑稱之為“ 引用鏈 ”。

當(dāng)一個(gè)對(duì)象到GC Roots沒有任何引用鏈相連的時(shí)候,證明此對(duì)象是可以被回收的。如下圖所示:

跟面試官聊到JVM,他99%會(huì)讓你談?wù)勥@個(gè)問題!cdn.xitu.io/2019/5/16/16abf61294833294?imageView2/0/w/1280/h/960/format/webp/ignore-error/1">

在Java中,可作為GC Roots對(duì)象的列表:

Java虛擬機(jī)棧中的引用對(duì)象。

本地方法棧中JNI(既一般說的Native方法)引用的對(duì)象。

方法區(qū)中類靜態(tài)常量的引用對(duì)象。

方法區(qū)中常量的引用對(duì)象。

對(duì)象生死與引用的關(guān)系

從上面的兩種算法來(lái)看,不管是引用計(jì)數(shù)法還是可達(dá)性分析算法都與對(duì)象的“引用”有關(guān),這說明:對(duì)象的引用決定了對(duì)象的生死。

那對(duì)象的引用都有那些呢?

在JDK1.2之前,引用的定義很傳統(tǒng):如果reference類型的數(shù)據(jù)中存儲(chǔ)的數(shù)值代表的是另一塊內(nèi)存的起始地址,就稱這塊內(nèi)存代表著一塊引用。

這樣的定義很純粹,但是也很狹隘,這種情況下一個(gè)對(duì)象要么被引用,要么沒引用,對(duì)于介于兩者之間的對(duì)象顯得無(wú)能為力。

JDK1.2之后對(duì)引用進(jìn)行了擴(kuò)充,將引用分為:

強(qiáng)引用 (Strong Reference)

軟引用 (Soft Reference)

弱引用 (Weak Reference)

虛引用 (Phantom Reference)

這也就是文章開頭第一個(gè)問題的答案,對(duì)象不是非生即死的,當(dāng)空間還足夠時(shí),還可以保留這些對(duì)象

如果空間不足時(shí),再拋棄這些對(duì)象。很多緩存功能的實(shí)現(xiàn)也符合這樣的場(chǎng)景。

強(qiáng)引用、軟引用、弱引用、虛引用,這4種引用的強(qiáng)度是依次遞減的。

強(qiáng)引用 :在代碼中普遍存在的,類似“Object obj = new Object()”這類引用,只要強(qiáng)引用還在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。

軟引用 :是一種相對(duì)強(qiáng)引用弱化一些的引用,可以讓對(duì)象豁免一些垃圾收集,只有當(dāng)jvm認(rèn)為內(nèi)存不足時(shí),才會(huì)去試圖回收軟引用指向的對(duì)象。 jvm會(huì)確保在拋出OutOfMemoryError之前,清理軟引用指向的對(duì)象。

弱引用 :非必需對(duì)象,但它的強(qiáng)度比軟引用更弱,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前。

虛引用 :也稱為幽靈引用或幻影引用,是最弱的一種引用關(guān)系,無(wú)法通過虛引用來(lái)獲取一個(gè)對(duì)象實(shí)例,為對(duì)象設(shè)置虛引用的目的只有一個(gè),就是當(dāng)著個(gè)對(duì)象被收集器回收時(shí)收到一條系統(tǒng)通知。

死亡標(biāo)記與拯救

在可達(dá)性算法中不可達(dá)的對(duì)象,并不是“非死不可”的,要真正宣告一個(gè)對(duì)象死亡,至少要經(jīng)歷兩次標(biāo)記的過程。

如果對(duì)象在進(jìn)行可達(dá)性分析之后,沒有與GC Roots相連接的引用鏈,它會(huì)被第一次標(biāo)記,并進(jìn)行篩選,篩選的條件是此對(duì)象是否有必要執(zhí)行finalize()方法。

執(zhí)行finalize()方法的兩個(gè)條件:

1、重寫了finalize()方法。

2、finalize()方法之前沒被調(diào)用過,因?yàn)閷?duì)象的finalize()方法只能被執(zhí)行一次。

如果滿足以上兩個(gè)條件,這個(gè)對(duì)象將會(huì)放置在F-Queue的隊(duì)列之中,并在稍后由一個(gè)虛擬機(jī)自建的、低優(yōu)先級(jí)Finalizer線程來(lái)執(zhí)行它。

對(duì)象的“自我拯救”

finalize()方法是對(duì)象脫離死亡命運(yùn)最后的機(jī)會(huì),如果對(duì)象在finalize()方法中重新與引用鏈上的任何一個(gè)對(duì)象建立關(guān)聯(lián)即可,比如把自己(this關(guān)鍵字)賦值給某個(gè)類變量或?qū)ο蟮某蓡T變量。

來(lái)看具體的實(shí)現(xiàn)代碼:

執(zhí)行的結(jié)果:

執(zhí)行finalize方法

我還活著

我已經(jīng)死了

從結(jié)果可以看出,任何對(duì)象的finalize()方法都只會(huì)被系統(tǒng)調(diào)用一次。

不建議使用finalize()方法來(lái)拯救對(duì)象 ,原因如下:

1、對(duì)象的finalize()只能執(zhí)行一次。

2、它的運(yùn)行代價(jià)高昂。

3、不確定性大。

4、無(wú)法保證各個(gè)對(duì)象的調(diào)用順序。

下面分享架構(gòu)師必會(huì)知識(shí)內(nèi)容

以下僅列舉了部分,文末有架構(gòu)師資料的獲取方法。

阿里P7架構(gòu)師談:分布式架構(gòu)核心組件之消息隊(duì)列

阿里P7架構(gòu)師談:跨域單點(diǎn)登錄分析及項(xiàng)目實(shí)戰(zhàn)

阿里P7架構(gòu)師談:站在設(shè)計(jì)者的角度思考Synchronized的設(shè)計(jì)原理

阿里P7架構(gòu)師談:分布式架構(gòu)通信基礎(chǔ)NIO原理解讀

阿里P7架構(gòu)師談:技術(shù)大師帶你玩轉(zhuǎn)Tomcat核心思想

阿里P7架構(gòu)師談:基于Netty手寫Dubbo框架

阿里P7架構(gòu)師談:深度分析并發(fā)編程的應(yīng)用及原理

阿里P7架構(gòu)師談:HashMap1.8源碼分析

阿里P7架構(gòu)師談:MySQL索引機(jī)制的探秘

阿里P7架構(gòu)師談:Redis互聯(lián)網(wǎng)應(yīng)用場(chǎng)景總結(jié)

阿里P7架構(gòu)師談:暢聊微服務(wù)架構(gòu)與敏捷開發(fā)

阿里P7架構(gòu)師談:想看源碼總暈車,方法技巧是關(guān)鍵

阿里P7架構(gòu)師談:分布式RPC手寫實(shí)現(xiàn).

阿里P7架構(gòu)師談:阿里面試p6必問之并發(fā)編程原理分析

阿里P7架構(gòu)師談:面試必問之JVM

阿里P7架構(gòu)師談:P7面試之Spring精華總結(jié)

領(lǐng)取方法

以上技術(shù)可以加入JAVA高級(jí)架構(gòu):705127209 群里面有阿里,百度,點(diǎn)評(píng),架構(gòu)師直播指導(dǎo),針對(duì)工作1--5的Java程序員提升自己,還有架構(gòu)學(xué)習(xí)資料,jvm,手寫springmvc,分布式,高可用,高性能,數(shù)據(jù)結(jié)構(gòu),springcloud,springboot 獲取。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI