Java虛擬機(jī)精選面試題20道
1.介紹下Java內(nèi)存區(qū)域(運(yùn)行時(shí)數(shù)據(jù)區(qū))。
Java虛擬機(jī)在執(zhí)行Java程序的過程中會(huì)把它所管理的內(nèi)存劃分為以下6個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域。
程序計(jì)數(shù)器(Program Counter Register)
一塊較小的內(nèi)存空間,可以看作當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。如果線程正在執(zhí)行的是一個(gè)Java方法,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址;如果正在執(zhí)行的是Native方法,這個(gè)計(jì)數(shù)器值則為空。
Java虛擬機(jī)棧(Java Virtual Machine Stacks)
與程序計(jì)數(shù)器一樣,Java虛擬機(jī)棧也是線程私有的,它的生命周期與線程相同。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。每一個(gè)方法從調(diào)用直至執(zhí)行完成的過程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過程。
本地方法棧(Native Method Stack)
本地方法棧與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,它們之間的區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則為虛擬機(jī)使用到的Native方法服務(wù)。
Java堆(Java Heap)
對(duì)大多數(shù)應(yīng)用來說,Java堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。
方法區(qū)(Method Area)
與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。方法區(qū)是JVM規(guī)范中定義的一個(gè)概念,具體放在哪里,不同的實(shí)現(xiàn)可以放在不同的地方。
運(yùn)行時(shí)常量池(Runtime Constant Pool)
運(yùn)行時(shí)常量池是方法區(qū)的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項(xiàng)信息是常量池,用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。
2.怎么判定對(duì)象已經(jīng)“死去”?
常見的判定方法有兩種:引用計(jì)數(shù)法和可達(dá)性分析算法,HotSpot中采用的是可達(dá)性分析算法。
引用計(jì)數(shù)法
給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加1;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1;任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的。
客觀地說,引用計(jì)數(shù)算法的實(shí)現(xiàn)簡單,判定效率也很高,在大部分情況下它都是一個(gè)不錯(cuò)的算法,但是主流的Java虛擬機(jī)里面沒有選用引用計(jì)數(shù)算法來管理內(nèi)存,其中最主要的原因是它很難解決對(duì)象之間相互循環(huán)引用的問題。
可達(dá)性分析算法
這個(gè)算法的基本思路就是通過一系列的稱為“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所走過的路徑稱為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒有任何引用鏈相連(用圖論的話來說,就是從GC Roots到這個(gè)對(duì)象不可達(dá))時(shí),則證明此對(duì)象是不可用的。如下圖所示,對(duì)象object 5、object 6、object 7雖然互相有關(guān)聯(lián),但是它們到GC Roots是不可達(dá)的,所以它們將會(huì)被判定為是可回收的對(duì)象。

3.介紹下四種引用(強(qiáng)引用、軟引用、弱引用、虛引用)?
強(qiáng)引用:在程序代碼之中普遍存在的,類似“Object obj=new Object()”這類的引用,只要強(qiáng)引用還存在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
軟引用:用來描述一些還有用但并非必需的對(duì)象,使用SoftReference類來實(shí)現(xiàn)軟引用,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收。
弱引用:用來描述非必需對(duì)象的,使用WeakReference類來實(shí)現(xiàn)弱引用,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前。
虛引用:是最弱的一種引用關(guān)系,使用PhantomReference類來實(shí)現(xiàn)虛引用,一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無法通過虛引用來取得一個(gè)對(duì)象實(shí)例。為一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。
4.垃圾收集有哪些算法,各自的特點(diǎn)? 標(biāo)記 - 清除算法
首先標(biāo)記出所有需要回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象。它的主要不足有兩個(gè):一個(gè)是效率問題,標(biāo)記和清除兩個(gè)過程的效率都不高;另一個(gè)是空間問題,標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過程中需要分配較大對(duì)象時(shí),無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。
復(fù)制算法
為了解決效率問題,一種稱為“復(fù)制”(Copying)的收集算法出現(xiàn)了,它將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊上面,然后再把已使用過的內(nèi)存空間一次清理掉。這樣使得每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況,只要移動(dòng)堆頂指針,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡單,運(yùn)行高效。只是這種算法的代價(jià)是將內(nèi)存縮小為了原來的一半,未免太高了一點(diǎn)。
標(biāo)記 - 整理算法
復(fù)制收集算法在對(duì)象存活率較高時(shí)就要進(jìn)行較多的復(fù)制操作,效率將會(huì)變低。更關(guān)鍵的是,如果不想浪費(fèi)50%的空間,就需要有額外的空間進(jìn)行分配擔(dān)保,以應(yīng)對(duì)被使用的內(nèi)存中所有對(duì)象都100%存活的極端情況,所以在老年代一般不能直接選用這種算法。
根據(jù)老年代的特點(diǎn),有人提出了另外一種“標(biāo)記-整理”(Mark-Compact)算法,標(biāo)記過程仍然與“標(biāo)記-清除”算法一樣,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活的對(duì)象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。
5.HotSpot為什么要分為新生代和老年代?
HotSpot根據(jù)對(duì)象存活周期的不同將內(nèi)存劃分為幾塊,一般是把Java堆分為新生代和老年代,這樣就可以根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴?。在新生代中,每次垃圾收集時(shí)都發(fā)現(xiàn)有大批對(duì)象死去,只有少量存活,那就選用復(fù)制算法,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集。而老年代中因?yàn)閷?duì)象存活率高、沒有額外空間對(duì)它進(jìn)行分配擔(dān)保,就必須使用“標(biāo)記—清理”或者“標(biāo)記—整理”算法來進(jìn)行回收。
其中新生代又分為1個(gè)Eden區(qū)和2個(gè)Survivor區(qū),通常稱為From Survivor和To Survivor區(qū)。

6.新生代中Eden區(qū)和Survivor區(qū)的默認(rèn)比例?
在HotSpot虛擬機(jī)中,Eden區(qū)和Survivor區(qū)的默認(rèn)比例為8:1:1,即-XX:SurvivorRatio=8,其中Survivor分為From Survivor和ToSurvivor,因此Eden此時(shí)占新生代空間的80%。
7.HotSpot GC的分類?
針對(duì)HotSpot VM的實(shí)現(xiàn),它里面的GC其實(shí)準(zhǔn)確分類只有兩大種:
- Partial GC:并不收集整個(gè)GC堆的模式,具體如下:
- Young GC/Minor GC:只收集新生代的GC。
- Old GC:只收集老年代的GC。只有CMS的concurrent collection是這個(gè)模式。
- Mixed GC:收集整個(gè)新生代以及部分老年代的GC,只有G1有這個(gè)模式。
- Full GC/Major GC:收集整個(gè)GC堆的模式,包括新生代、老年代、永久代(如果存在的話)等所有部分的模式。
8.HotSpot GC的觸發(fā)條件?
這里只說常見的Young GC和Full GC。
Young GC:當(dāng)新生代中的Eden區(qū)沒有足夠空間進(jìn)行分配時(shí)會(huì)觸發(fā)Young GC。
Full GC:
- 當(dāng)準(zhǔn)備要觸發(fā)一次Young GC時(shí),如果發(fā)現(xiàn)統(tǒng)計(jì)數(shù)據(jù)說之前Young GC的平均晉升大小比目前老年代剩余的空間大,則不會(huì)觸發(fā)Young GC而是轉(zhuǎn)為觸發(fā)Full GC。(通常情況)
- 如果有永久代的話,在永久代需要分配空間但已經(jīng)沒有足夠空間時(shí),也要觸發(fā)一次Full GC。
- System.gc()默認(rèn)也是觸發(fā)Full GC。
- heap dump帶GC默認(rèn)也是觸發(fā)Full GC。
- CMS GC時(shí)出現(xiàn)Concurrent Mode Failure會(huì)導(dǎo)致一次Full GC的產(chǎn)生。
9.Full GC后老年代的空間反而變???
HotSpot的Full GC實(shí)現(xiàn)中,默認(rèn)新生代里所有活的對(duì)象都要晉升到老年代,實(shí)在晉升不了才會(huì)留在新生代。假如做Full GC的時(shí)候,老年代里的對(duì)象幾乎沒有死掉的,而新生代又要晉升活對(duì)象上來,那么Full GC結(jié)束后老年代的使用量自然就上升了。
10.什么情況下新生代對(duì)象會(huì)晉升到老年代?
- 如果新生代的垃圾收集器為Serial和ParNew,并且設(shè)置了-XX:PretenureSizeThreshold參數(shù),當(dāng)對(duì)象大于這個(gè)參數(shù)值時(shí),會(huì)被認(rèn)為是大對(duì)象,直接進(jìn)入老年代。
- Young GC后,如果對(duì)象太大無法進(jìn)入Survivor區(qū),則會(huì)通過分配擔(dān)保機(jī)制進(jìn)入老年代。
- 對(duì)象每在Survivor區(qū)中“熬過”一次Young GC,年齡就增加1歲,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲,可以通過-XX:MaxTenuringThreshold設(shè)置),就將會(huì)被晉升到老年代中。
- 如果在Survivor區(qū)中相同年齡所有對(duì)象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對(duì)象就可以直接進(jìn)入老年代,無須等到MaxTenuringThreshold中要求的年齡。
11.介紹下垃圾收集機(jī)制(在什么時(shí)候,對(duì)什么,做了什么)? 在什么時(shí)候?
在觸發(fā)GC的時(shí)候,具體如下,這里只說常見的Young GC和Full GC。
觸發(fā)Young GC:當(dāng)新生代中的Eden區(qū)沒有足夠空間進(jìn)行分配時(shí)會(huì)觸發(fā)Young GC。
觸發(fā)Full GC:
- 當(dāng)準(zhǔn)備要觸發(fā)一次Young GC時(shí),如果發(fā)現(xiàn)統(tǒng)計(jì)數(shù)據(jù)說之前Young GC的平均晉升大小比目前老年代剩余的空間大,則不會(huì)觸發(fā)Young GC而是轉(zhuǎn)為觸發(fā)Full GC。(通常情況)
- 如果有永久代的話,在永久代需要分配空間但已經(jīng)沒有足夠空間時(shí),也要觸發(fā)一次Full GC。
- System.gc()默認(rèn)也是觸發(fā)Full GC。
- heap dump帶GC默認(rèn)也是觸發(fā)Full GC。
- CMS GC時(shí)出現(xiàn)Concurrent Mode Failure會(huì)導(dǎo)致一次Full GC的產(chǎn)生。
對(duì)什么?
對(duì)那些JVM認(rèn)為已經(jīng)“死掉”的對(duì)象。即從GC Root開始搜索,搜索不到的,并且經(jīng)過一次篩選標(biāo)記沒有復(fù)活的對(duì)象。
做了什么?
對(duì)這些JVM認(rèn)為已經(jīng)“死掉”的對(duì)象進(jìn)行垃圾收集,新生代使用復(fù)制算法,老年代使用標(biāo)記-清除和標(biāo)記-整理算法。
12.GC Root有哪些?
在Java語言中,可作為GC Roots的對(duì)象包括下面幾種:
- 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象。
- 方法區(qū)中類靜態(tài)屬性引用的對(duì)象。
- 方法區(qū)中常量引用的對(duì)象。
- 本地方法棧中JNI(即一般說的Native方法)引用的對(duì)象。
13.發(fā)生Young GC的時(shí)候需要掃描老年代的對(duì)象嗎?
在分代收集中,新生代的規(guī)模一般都比老年代要小許多,新生代的收集也比老年代要頻繁許多,如果回收新生代時(shí)也不得不同時(shí)掃描老年代的話,那么Young GC的效率可能下降不少。顯然是不可能區(qū)掃描老年代的,那么是通過什么辦法來解決這個(gè)問題了?
在大多垃圾收集器中(G1有不同的地方),通過CardTable來維護(hù)老年代對(duì)年輕代的引用,CardTable可以說是Remembered Set(RS)的一種特殊實(shí)現(xiàn),是Card的集合。Card是一塊2的冪字節(jié)大小的內(nèi)存區(qū)域,例如HotSpot用512字節(jié),里面可能包含多個(gè)對(duì)象。CardTable要記錄的是從它覆蓋的范圍出發(fā)指向別的范圍的指針。以分代式GC的CardTable為例,要記錄老年代指向年輕代的跨代指針,被標(biāo)記的Card是老年代范圍內(nèi)的。當(dāng)進(jìn)行年輕代的垃圾收集時(shí),只需要掃描年輕代和老年代的CardTable即可保證不對(duì)全堆掃描也不會(huì)有遺漏。CardTable通常為字節(jié)數(shù)組,由Card的索引(即數(shù)組下標(biāo))來標(biāo)識(shí)每個(gè)分區(qū)的空間地址。
14.垃圾收集器有哪些?
目前HotSpot中有7種作用于不同分代的收集器,如下圖所示,如果兩個(gè)收集器之間存在連線,就說明它們可以搭配使用。

15.介紹CMS垃圾收集器的特點(diǎn)?
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器。目前很大一部分的Java應(yīng)用集中在互聯(lián)網(wǎng)站或者B/S系統(tǒng)的服務(wù)端上,這類應(yīng)用尤其重視服務(wù)的響應(yīng)速度,希望系統(tǒng)停頓時(shí)間最短,以給用戶帶來較好的體驗(yàn)。CMS收集器就非常符合這類應(yīng)用的需求。
從名字(包含“Mark Sweep”)上就可以看出,CMS收集器是基于“標(biāo)記—清除”算法實(shí)現(xiàn)的,它的運(yùn)作過程可以分為6個(gè)步驟,包括:初始標(biāo)記、并發(fā)標(biāo)記、預(yù)處理、重新標(biāo)記、并發(fā)清除、重置。
CMS是一款優(yōu)秀的收集器,它的主要優(yōu)點(diǎn)在名字上已經(jīng)體現(xiàn)出來了:并發(fā)收集、低停頓,但是CMS還遠(yuǎn)達(dá)不到完美的程度,它有以下3個(gè)明顯的缺點(diǎn):
- CMS收集器對(duì)CPU資源非常敏感。
- CMS收集器無法處理浮動(dòng)垃圾(Floating Garbage),可能出現(xiàn)“Concurrent Mode Failure”失敗而導(dǎo)致另一次Full GC的產(chǎn)生。
- CMS是一款基于“標(biāo)記—清除”算法實(shí)現(xiàn)的收集器,這意味著收集結(jié)束時(shí)會(huì)有大量空間碎片產(chǎn)生。
16.介紹下G1垃圾收集器的特點(diǎn)?(較復(fù)雜,可以考慮跳過)
G1(Garbage-First)收集器是當(dāng)今收集器技術(shù)發(fā)展的最前沿成果之一。G1是一款面向服務(wù)端應(yīng)用的垃圾收集器。與其他GC收集器相比,G1具備如下特點(diǎn):并行與并發(fā)、分代收集、空間整合、可預(yù)測的停頓。
在G1之前的其他收集器進(jìn)行收集的范圍都是整個(gè)新生代或者老年代,而G1不再是這樣。使用G1收集器時(shí),Java堆的內(nèi)存布局就與其他收集器有很大差別,它將整個(gè)Java堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域,雖然還保留有新生代和老年代的概念,但新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續(xù))的集合。
G1收集器之所以能建立可預(yù)測的停頓時(shí)間模型,是因?yàn)樗梢杂杏?jì)劃地避免在整個(gè)Java堆中進(jìn)行全區(qū)域的垃圾收集。G1跟蹤各個(gè)Region里面的垃圾堆積的價(jià)值大?。ɑ厥账@得的空間大小以及回收所需時(shí)間的經(jīng)驗(yàn)值),在后臺(tái)維護(hù)一個(gè)優(yōu)先列表,每次根據(jù)允許的收集時(shí)間,優(yōu)先回收價(jià)值最大的Region(這也就是Garbage-First名稱的來由)。這種使用Region劃分內(nèi)存空間以及有優(yōu)先級(jí)的區(qū)域回收方式,保證了G1收集器在有限的時(shí)間內(nèi)可以獲取盡可能高的收集效率。
Mixed GC是G1垃圾收集器特有的收集方式,Mixed GC大致可劃分為全局并發(fā)標(biāo)記(global concurrent marking)和拷貝存活對(duì)象(evacuation)兩個(gè)大部分:
global concurrent marking是基于SATB形式的并發(fā)標(biāo)記,包括以下4個(gè)階段:初始標(biāo)記(Initial Marking)、并發(fā)標(biāo)記(Concurrent Marking)、最終標(biāo)記(Final Marking)、清理(Clean Up)。Evacuation階段是全暫停的。它負(fù)責(zé)把一部分region里的活對(duì)象拷貝到空region里去,然后回收原本的region的空間。
17.類加載的過程。
類從被加載到虛擬機(jī)內(nèi)存中開始,到卸載出內(nèi)存為止,它的整個(gè)生命周期包括:加載、驗(yàn)證、準(zhǔn)備、解析、初始化、使用和卸載7個(gè)階段。其中驗(yàn)證、準(zhǔn)備、解析3個(gè)部分統(tǒng)稱為連接。
加載:
“類加載”過程的一個(gè)階段,在加載階段,虛擬機(jī)需要完成以下3件事情:
通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口。
驗(yàn)證:
連接階段的第一步,這一階段的目的是為了確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。從整體上看,驗(yàn)證階段大致上會(huì)完成下面4個(gè)階段的檢驗(yàn)動(dòng)作:文件格式驗(yàn)證、元數(shù)據(jù)驗(yàn)證、字節(jié)碼驗(yàn)證、符號(hào)引用驗(yàn)證。
準(zhǔn)備:
該階段是正式為類變量(static修飾的變量)分配內(nèi)存并設(shè)置類變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。這里所說的初始值“通常情況”下是數(shù)據(jù)類型的零值,下表列出了Java中所有基本數(shù)據(jù)類型的零值。

解析:
該階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過程。
初始化:
初始化階段是執(zhí)行類構(gòu)造器<clinit>()方法的過程。<clinit>()方法是由編譯器自動(dòng)收集類中的所有類變量(static修飾的變量)的賦值動(dòng)作和靜態(tài)語句塊(static{}塊)中的語句合并產(chǎn)生的,編譯器收集的順序是由語句在源文件中出現(xiàn)的順序所決定的。如果該類存在父類,則虛擬機(jī)會(huì)保證在執(zhí)行子類的<clinit>()方法前,父類的<clinit>()方法已經(jīng)執(zhí)行完畢。因此在虛擬機(jī)中第一個(gè)被執(zhí)行<clinit>()方法的類肯定是java.lang.Object。
18.Java虛擬機(jī)中有哪些類加載器?
從Java虛擬機(jī)的角度來講,只存在兩種不同的類加載器:一種是啟動(dòng)類加載器(Bootstrap ClassLoader),這個(gè)類加載器使用C++語言實(shí)現(xiàn),是虛擬機(jī)自身的一部分;另一種就是所有其他的類加載器,這些類加載器都由Java語言實(shí)現(xiàn),獨(dú)立于虛擬機(jī)外部,并且全都繼承自抽象類java.lang.ClassLoader。
從Java開發(fā)人員的角度來看,絕大部分Java程序都會(huì)使用到以下3種系統(tǒng)提供的類加載器。
啟動(dòng)類加載器(Bootstrap ClassLoader):
這個(gè)類加載器負(fù)責(zé)將存放在<JAVA_HOME>\lib目錄中的,或者被-Xbootclasspath參數(shù)所指定的路徑中的,并且是虛擬機(jī)識(shí)別的(僅按照文件名識(shí)別,如rt.jar,名字不符合的類庫即使放在lib目錄中也不會(huì)被加載)類庫加載到虛擬機(jī)內(nèi)存中。
擴(kuò)展類加載器(Extension ClassLoader):
這個(gè)加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),它負(fù)責(zé)加載<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫,開發(fā)者可以直接使用擴(kuò)展類加載器。
應(yīng)用程序類加載器(Application ClassLoader):
這個(gè)類加載器由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。由于這個(gè)類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也稱它為系統(tǒng)類加載器。它負(fù)責(zé)加載用戶類路徑(ClassPath)上所指定的類庫,開發(fā)者可以直接使用這個(gè)類加載器,如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況下這個(gè)就是程序中默認(rèn)的類加載器。
我們的應(yīng)用程序都是由這3種類加載器互相配合進(jìn)行加載的,如果有必要,還可以加入自己定義的類加載器。這些類加載器之間的關(guān)系一般如圖所示。

19.什么是雙親委派模型?
如果一個(gè)類加載器收到了類加載的請(qǐng)求,它首先不會(huì)自己去嘗試加載這個(gè)類,而是把這個(gè)請(qǐng)求委派給父類加載器去完成,每一個(gè)層次的類加載器都是如此,因此所有的加載請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類加載器中,只有當(dāng)父加載器反饋?zhàn)约簾o法完成這個(gè)加載請(qǐng)求(它的搜索范圍中沒有找到所需的類)時(shí),子加載器才會(huì)嘗試自己去加載。
20.使用雙親委派模型的好處?
使用雙親委派模型來組織類加載器之間的關(guān)系,有一個(gè)顯而易見的好處就是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系。例如類java.lang.Object,它存放在rt.jar之中,無論哪一個(gè)類加載器要加載這個(gè)類,最終都是委派給處于模型最頂端的啟動(dòng)類加載器進(jìn)行加載,因此Object類在程序的各種類加載器環(huán)境中都是同一個(gè)類。相反,如果沒有使用雙親委派模型,由各個(gè)類加載器自行去加載的話,如果用戶自己編寫了一個(gè)稱為java.lang.Object的類,并放在程序的ClassPath中,那系統(tǒng)中將會(huì)出現(xiàn)多個(gè)不同的Object類,Java 類型體系中最基礎(chǔ)的行為也就無法保證,應(yīng)用程序也將會(huì)變得一片混亂。
總結(jié)
這篇JAVA虛擬機(jī)·面試題的總結(jié)就到這了,希望大家可以多多關(guān)注腳本之家的其他精彩文章!
相關(guān)文章
Springboot整合JPA配置多數(shù)據(jù)源流程詳解
這篇文章主要介紹了Springboot整合JPA配置多數(shù)據(jù)源,JPA可以通過實(shí)體類生成數(shù)據(jù)庫的表,同時(shí)自帶很多增刪改查方法,大部分sql語句不需要我們自己寫,配置完成后直接調(diào)用方法即可,很方便2022-11-11
基于Mybatis-Plus攔截器實(shí)現(xiàn)MySQL數(shù)據(jù)加解密的示例代碼
用戶的一些敏感數(shù)據(jù),例如手機(jī)號(hào)、郵箱、身份證等信息,在數(shù)據(jù)庫以明文存儲(chǔ)時(shí)會(huì)存在數(shù)據(jù)泄露的風(fēng)險(xiǎn),因此需要進(jìn)行加密,解密等功能,接下來本文就給大家介紹基于Mybatis-Plus攔截器實(shí)現(xiàn)MySQL數(shù)據(jù)加解密,需要的朋友可以參考下2023-07-07
spring-boot整合dubbo:Spring-boot-dubbo-starter
這篇文章主要介紹了spring-boot整合dubbo:Spring-boot-dubbo-starter的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-05-05
java8新特性-Stream入門學(xué)習(xí)心得
這篇文章主要介紹了java8新特性-Stream入門學(xué)習(xí)心得,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
從底層源碼深入分析Spring的IoC容器的實(shí)現(xiàn)原理
IoC容器負(fù)責(zé)管理對(duì)象的生命周期和依賴關(guān)系,大大簡化了應(yīng)用程序的開發(fā)和維,我們這篇文章將會(huì)從底層源碼的角度深入分析Spring的IoC容器實(shí)現(xiàn),探索它的工作原理和關(guān)鍵組件,需要的朋友可以參考下2023-07-07
Spring Boot中使用 Spring Security 構(gòu)建權(quán)限系統(tǒng)的示例代碼
本篇文章主要介紹了Spring Boot中使用 Spring Security 構(gòu)建權(quán)限系統(tǒng)的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08

