Java面試題沖刺第二十九天--JVM3
面試題1:如何判斷對(duì)象是否存活
對(duì)于判斷對(duì)象是否存活,主要是兩種基本算法,引用計(jì)數(shù)和可達(dá)性分析,目前java主要采用的是可達(dá)性分析算法
1.引用計(jì)數(shù)算法
判斷對(duì)象是否存活的方式如:在對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加一;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減一;任何時(shí)刻計(jì)數(shù)器為零的對(duì)象就是不可能再被使用的。
其優(yōu)點(diǎn)是實(shí)現(xiàn)簡(jiǎn)單,判定效率高;缺點(diǎn)是該算法有很多例外情況要考慮,必須要配合大量額外處理才能保證正確地工作,且存在一個(gè)基本的難題,也就是很難處理循環(huán)引用關(guān)系。
2.可達(dá)性分析算法
其原理簡(jiǎn)單來(lái)說(shuō),就是將對(duì)象及其引用關(guān)系看作一個(gè)圖,通過(guò)一系列稱為GC Roots的根對(duì)象作為起始節(jié)點(diǎn)集,從這些節(jié)點(diǎn)開始,通過(guò)引用關(guān)系向下搜索,搜索過(guò)程所走過(guò)的路徑稱為引用鏈(Reference Chain),如果一個(gè)對(duì)象和 GC Roots 之間不可達(dá),也就是不存在引用鏈條,那么即認(rèn)為是可回收對(duì)象。JVM會(huì)把虛擬機(jī)棧和本地方法棧中正在引用的對(duì)象、靜態(tài)屬性引用的對(duì)象和常量,作為 GC Roots。

如圖所示,對(duì)象object 5、object 6、object 7雖然互有關(guān)聯(lián),但是它們到GC Roots是不可達(dá)的, 因此它們將會(huì)被判定為可回收的對(duì)象。
面試題2:哪些對(duì)象可以作為GC Roots?
在Java技術(shù)體系里面,固定可作為GC(Garbage Collector) Roots的對(duì)象包括以下幾種:

常說(shuō)的GC(Garbage Collector) roots,特指的是垃圾收集器的根對(duì)象(GC Root Object),也叫作稱為GC垃圾回收根(GC Root),GC會(huì)收集那些不是GC roots且沒有被GC roots引用的對(duì)象清理掉。
一個(gè)對(duì)象可以屬于多個(gè)root,GC root存在幾下種:
- 虛擬機(jī)棧中引用 的對(duì)象
- 如各個(gè)線程被調(diào)用的方法堆棧中使用到的 參數(shù)、局部變量、臨時(shí)變量等。
- 方法區(qū)中類靜態(tài)屬性引用的對(duì)象
- 如Java 類的引用類型靜態(tài)變量
- 方法區(qū)中常量引用的對(duì)象
- 如字符串常量池(String Table) 里的引用
- 本地方法棧內(nèi) JNI(通常說(shuō)的本地方法)引用的對(duì)象
- 所有被同步鎖 (synchronized關(guān)鍵字) 持有的對(duì)象
- Java 虛擬機(jī)內(nèi)部的引用
- 如基本數(shù)據(jù)類型對(duì)應(yīng)的Class對(duì)象,一些常駐的異常對(duì)象(比如 NullPointExcepiton、OutOfMemoryError)、系統(tǒng)類加載器等。
- 反映 Java 虛擬機(jī)內(nèi)部情況的 JMXBean、JVMTI 中注冊(cè)的回調(diào)、本地代碼緩存等。
- 除了固定的 GC Roots 集合以外,根據(jù)用戶所選用的垃圾收集器以及當(dāng)前回收的內(nèi)存區(qū)域不同,還可以有其他對(duì)象 臨時(shí)性 地加入,共同構(gòu)成完整 GC Roots 集合。
面試題3:你了解的對(duì)象引用方式都有哪些?
該回答來(lái)自極客時(shí)間《Java核心技術(shù)面試精講第四講》的評(píng)論部分。
在Java語(yǔ)言中,除了基本數(shù)據(jù)類型外,其他的都是指向各類對(duì)象的對(duì)象引用;Java中根據(jù)其生命周期的長(zhǎng)短,將引用分為強(qiáng)引用、弱引用、軟引用、虛引用4類。
1 強(qiáng)引用
我們平常典型編碼Object obj = new Object()中的obj就是強(qiáng)引用。通過(guò)關(guān)鍵字new創(chuàng)建的對(duì)象所關(guān)聯(lián)的引用就是強(qiáng)引用。 當(dāng)JVM內(nèi)存空間不足,JVM寧愿拋出OutOfMemoryError運(yùn)行時(shí)錯(cuò)誤(OOM),使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的存活對(duì)象來(lái)解決內(nèi)存不足的問(wèn)題。對(duì)于一個(gè)普通的對(duì)象,如果沒有其他的引用關(guān)系,只要超過(guò)了引用的作用域或者顯式地將相應(yīng)(強(qiáng))引用賦值為null,就是可以被垃圾收集的了,具體回收時(shí)機(jī)還是要看垃圾收集策略。
2 軟引用
軟引用通過(guò)SoftReference類實(shí)現(xiàn)。
軟引用的生命周期比強(qiáng)引用短一些。只有當(dāng) JVM 認(rèn)為內(nèi)存不足時(shí),才會(huì)去試圖回收軟引用指向的對(duì)象:即JVM 會(huì)確保在拋出OutOfMemoryError之前,清理軟引用指向的對(duì)象。軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被垃圾回收器回收,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。后續(xù),我們可以調(diào)用ReferenceQueue.poll()方法來(lái)檢查是否有它所關(guān)心的對(duì)象被回收。如果隊(duì)列為空,將返回一個(gè)null,否則該方法返回隊(duì)列中前面的一個(gè)Reference對(duì)象。
應(yīng)用場(chǎng)景:軟引用通常用來(lái)實(shí)現(xiàn)內(nèi)存敏感的緩存。如果還有空閑內(nèi)存,就可以暫時(shí)保留緩存,當(dāng)內(nèi)存不足時(shí)清理掉,這樣就保證了使用緩存的同時(shí),不會(huì)耗盡內(nèi)存。
3 弱引用
弱引用通過(guò)WeakReference類實(shí)現(xiàn)。
弱引用的生命周期比軟引用短。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過(guò)程中,一旦發(fā)現(xiàn)了具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存。由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快回收弱引用的對(duì)象。弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回收,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
應(yīng)用場(chǎng)景:弱引用同樣可用于內(nèi)存敏感的緩存。
4 虛引用
虛引用也叫幻象引用,通過(guò)PhantomReference類來(lái)實(shí)現(xiàn)。
無(wú)法通過(guò)虛引用訪問(wèn)對(duì)象的任何屬性或函數(shù)。幻象引用僅僅是提供了一種確保對(duì)象被 finalize 以后,做某些事情的機(jī)制。如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收。虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前,把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
ReferenceQueue queue = new ReferenceQueue (); PhantomReference pr = new PhantomReference (object, queue);
程序可以通過(guò)判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來(lái)了解被引用的對(duì)象是否將要被垃圾回收。如果程序發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取一些程序行動(dòng)。
應(yīng)用場(chǎng)景:可用來(lái)跟蹤對(duì)象被垃圾回收器回收的活動(dòng),當(dāng)一個(gè)虛引用關(guān)聯(lián)的對(duì)象被垃圾收集器回收之前會(huì)收到一條系統(tǒng)通知。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java 使用線程池執(zhí)行多個(gè)任務(wù)的示例
這篇文章主要介紹了Java 使用線程池執(zhí)行多個(gè)任務(wù)的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-03-03
SpringBoot整合Netty實(shí)現(xiàn)WebSocket的示例代碼
本文主要介紹了SpringBoot整合Netty實(shí)現(xiàn)WebSocket的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
JAVA Stack詳細(xì)介紹和示例學(xué)習(xí)
JAVA Stack是棧。它的特性是:先進(jìn)后出(FILO, First In Last Out)。2013-11-11
java發(fā)起http請(qǐng)求調(diào)用post與get接口的方法實(shí)例
在實(shí)際開發(fā)過(guò)程中,我們經(jīng)常需要調(diào)用對(duì)方提供的接口或測(cè)試自己寫的接口是否合適,下面這篇文章主要給大家介紹了關(guān)于java發(fā)起http請(qǐng)求調(diào)用post與get接口的相關(guān)資料,需要的朋友可以參考下2022-08-08
SpringBoot訪問(wèn)靜態(tài)資源的配置及順序說(shuō)明
這篇文章主要介紹了SpringBoot訪問(wèn)靜態(tài)資源的配置及順序說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03

