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)開(kāi)始,通過(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且沒(méi)有被GC roots引用的對(duì)象清理掉。
一個(gè)對(duì)象可以屬于多個(gè)root,GC root存在幾下種:
- 虛擬機(jī)棧中引用 的對(duì)象
- 如各個(gè)線程被調(diào)用的方法堆棧中使用到的 參數(shù)、局部變量、臨時(shí)變量等。
- 方法區(qū)中類(lèi)靜態(tài)屬性引用的對(duì)象
- 如Java 類(lèi)的引用類(lèi)型靜態(tài)變量
- 方法區(qū)中常量引用的對(duì)象
- 如字符串常量池(String Table) 里的引用
- 本地方法棧內(nèi) JNI(通常說(shuō)的本地方法)引用的對(duì)象
- 所有被同步鎖 (synchronized關(guān)鍵字) 持有的對(duì)象
- Java 虛擬機(jī)內(nèi)部的引用
- 如基本數(shù)據(jù)類(lèi)型對(duì)應(yīng)的Class對(duì)象,一些常駐的異常對(duì)象(比如 NullPointExcepiton、OutOfMemoryError)、系統(tǒng)類(lèi)加載器等。
- 反映 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ù)類(lèi)型外,其他的都是指向各類(lèi)對(duì)象的對(duì)象引用;Java中根據(jù)其生命周期的長(zhǎng)短,將引用分為強(qiáng)引用、弱引用、軟引用、虛引用4類(lèi)。
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ì)象,如果沒(méi)有其他的引用關(guān)系,只要超過(guò)了引用的作用域或者顯式地將相應(yīng)(強(qiáng))引用賦值為null,就是可以被垃圾收集的了,具體回收時(shí)機(jī)還是要看垃圾收集策略。
2 軟引用
軟引用通過(guò)SoftReference
類(lèi)實(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類(lèi)實(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)來(lái)實(shí)現(xiàn)。
無(wú)法通過(guò)虛引用訪問(wèn)對(duì)象的任何屬性或函數(shù)?;孟笠脙H僅是提供了一種確保對(duì)象被 finalize 以后,做某些事情的機(jī)制。如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒(méi)有任何引用一樣,在任何時(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中Long類(lèi)型傳入前端數(shù)值出錯(cuò)問(wèn)題
這篇文章主要介紹了Java中Long類(lèi)型傳入前端數(shù)值出錯(cuò)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04區(qū)分Java中的ArrayList和LinkedList
這篇文章主要介紹了如何區(qū)分Java中ArrayList和LinkedList,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-06-06MyBatis之傳入?yún)?shù)為list、數(shù)組、map的寫(xiě)法
這篇文章主要介紹了MyBatis之傳入?yún)?shù)為list、數(shù)組、map的寫(xiě)法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11如何在Intellij中安裝LeetCode刷題插件方便Java刷題
這篇文章主要介紹了如何在Intellij中安裝LeetCode刷題插件方便Java刷題,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08IDEA中用maven連接數(shù)據(jù)庫(kù)的教程
這篇文章主要介紹了IDEA中用maven連接數(shù)據(jù)庫(kù)的教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11解析Spring框架中的XmlBeanDefinitionStoreException異常情況
這篇文章主要介紹了解析Spring框架中的XmlBeanDefinitionStoreException異常情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04spring-boot-maven-plugin 插件的作用詳解
添加了spring-boot-maven-plugin插件后,當(dāng)運(yùn)行maven打包的命令,項(xiàng)目會(huì)被打包成一個(gè)可以直接運(yùn)行的jar包,使用"java -jar"可以直接運(yùn)行。這篇文章主要給大家介紹spring-boot-maven-plugin 插件的作用,感興趣的朋友一起看看吧2018-10-10MyEclipse整合ssh三大框架環(huán)境搭載用戶注冊(cè)源碼下載
這篇文章主要為大家詳細(xì)介紹了如何使用MyEclipse整合ssh三大框架進(jìn)行環(huán)境搭載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10