欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java虛擬機(jī)精選面試題20道

 更新時(shí)間:2021年06月16日 17:36:37   作者:程序員囧輝  
現(xiàn)在面試Java開(kāi)發(fā)時(shí),基本都會(huì)問(wèn)到Java虛擬機(jī)的知識(shí),根據(jù)職位不同問(wèn)的內(nèi)容深淺又有所區(qū)別。本文整理了10道面試中常問(wèn)的Java虛擬機(jī)面試題,希望對(duì)正在面試的同學(xué)有所幫助

1.介紹下Java內(nèi)存區(qū)域(運(yùn)行時(shí)數(shù)據(jù)區(qū))。

Java虛擬機(jī)在執(zhí)行Java程序的過(guò)程中會(huì)把它所管理的內(nèi)存劃分為以下6個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域。

程序計(jì)數(shù)器(Program Counter Register)

一塊較小的內(nèi)存空間,可以看作當(dāng)前線(xiàn)程所執(zhí)行的字節(jié)碼的行號(hào)指示器。如果線(xiàn)程正在執(zhí)行的是一個(gè)Java方法,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址;如果正在執(zhí)行的是Native方法,這個(gè)計(jì)數(shù)器值則為空。

Java虛擬機(jī)棧(Java Virtual Machine Stacks)

與程序計(jì)數(shù)器一樣,Java虛擬機(jī)棧也是線(xiàn)程私有的,它的生命周期與線(xiàn)程相同。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。每一個(gè)方法從調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過(guò)程。

本地方法棧(Native Method Stack)

本地方法棧與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,它們之間的區(qū)別不過(guò)是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則為虛擬機(jī)使用到的Native方法服務(wù)。

Java堆(Java Heap)

對(duì)大多數(shù)應(yīng)用來(lái)說(shuō),Java堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線(xiàn)程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。

方法區(qū)(Method Area)

與Java堆一樣,是各個(gè)線(xiàn)程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。方法區(qū)是JVM規(guī)范中定義的一個(gè)概念,具體放在哪里,不同的實(shí)現(xiàn)可以放在不同的地方。

運(yùn)行時(shí)常量池(Runtime Constant Pool)

運(yùn)行時(shí)常量池是方法區(qū)的一部分。Class文件中除了有類(lèi)的版本、字段、方法、接口等描述信息外,還有一項(xiàng)信息是常量池,用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類(lèi)加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。

2.怎么判定對(duì)象已經(jīng)“死去”?

常見(jiàn)的判定方法有兩種:引用計(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ì)象就是不可能再被使用的。

客觀(guān)地說(shuō),引用計(jì)數(shù)算法的實(shí)現(xiàn)簡(jiǎn)單,判定效率也很高,在大部分情況下它都是一個(gè)不錯(cuò)的算法,但是主流的Java虛擬機(jī)里面沒(méi)有選用引用計(jì)數(shù)算法來(lái)管理內(nèi)存,其中最主要的原因是它很難解決對(duì)象之間相互循環(huán)引用的問(wèn)題。

可達(dá)性分析算法

這個(gè)算法的基本思路就是通過(guò)一系列的稱(chēng)為“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索所走過(guò)的路徑稱(chēng)為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連(用圖論的話(huà)來(lái)說(shuō),就是從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)引用:在程序代碼之中普遍存在的,類(lèi)似“Object obj=new Object()”這類(lèi)的引用,只要強(qiáng)引用還存在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。

軟引用:用來(lái)描述一些還有用但并非必需的對(duì)象,使用SoftReference類(lèi)來(lái)實(shí)現(xiàn)軟引用,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收。

弱引用:用來(lái)描述非必需對(duì)象的,使用WeakReference類(lèi)來(lái)實(shí)現(xiàn)弱引用,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前。

虛引用:是最弱的一種引用關(guān)系,使用PhantomReference類(lèi)來(lái)實(shí)現(xiàn)虛引用,一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無(wú)法通過(guò)虛引用來(lái)取得一個(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è)是效率問(wèn)題,標(biāo)記和清除兩個(gè)過(guò)程的效率都不高;另一個(gè)是空間問(wèn)題,標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。

復(fù)制算法

為了解決效率問(wèn)題,一種稱(chēng)為“復(fù)制”(Copying)的收集算法出現(xiàn)了,它將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊上面,然后再把已使用過(guò)的內(nèi)存空間一次清理掉。這樣使得每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況,只要移動(dòng)堆頂指針,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效。只是這種算法的代價(jià)是將內(nèi)存縮小為了原來(lá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)記過(guò)程仍然與“標(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ì)象存活率高、沒(méi)有額外空間對(duì)它進(jìn)行分配擔(dān)保,就必須使用“標(biāo)記—清理”或者“標(biāo)記—整理”算法來(lái)進(jìn)行回收。

其中新生代又分為1個(gè)Eden區(qū)和2個(gè)Survivor區(qū),通常稱(chēng)為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的分類(lèi)?

針對(duì)HotSpot VM的實(shí)現(xiàn),它里面的GC其實(shí)準(zhǔn)確分類(lèi)只有兩大種:

  1. Partial GC:并不收集整個(gè)GC堆的模式,具體如下:
    1. Young GC/Minor GC:只收集新生代的GC。
    2. Old GC:只收集老年代的GC。只有CMS的concurrent collection是這個(gè)模式。
    3. Mixed GC:收集整個(gè)新生代以及部分老年代的GC,只有G1有這個(gè)模式。
  2. Full GC/Major GC:收集整個(gè)GC堆的模式,包括新生代、老年代、永久代(如果存在的話(huà))等所有部分的模式。

8.HotSpot GC的觸發(fā)條件?

這里只說(shuō)常見(jiàn)的Young GC和Full GC。

Young GC:當(dāng)新生代中的Eden區(qū)沒(méi)有足夠空間進(jìn)行分配時(shí)會(huì)觸發(fā)Young GC。

Full GC:

  1. 當(dāng)準(zhǔn)備要觸發(fā)一次Young GC時(shí),如果發(fā)現(xiàn)統(tǒng)計(jì)數(shù)據(jù)說(shuō)之前Young GC的平均晉升大小比目前老年代剩余的空間大,則不會(huì)觸發(fā)Young GC而是轉(zhuǎn)為觸發(fā)Full GC。(通常情況)
  2. 如果有永久代的話(huà),在永久代需要分配空間但已經(jīng)沒(méi)有足夠空間時(shí),也要觸發(fā)一次Full GC。
  3. System.gc()默認(rèn)也是觸發(fā)Full GC。
  4. heap dump帶GC默認(rèn)也是觸發(fā)Full GC。
  5. 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ì)象幾乎沒(méi)有死掉的,而新生代又要晉升活對(duì)象上來(lái),那么Full GC結(jié)束后老年代的使用量自然就上升了。

10.什么情況下新生代對(duì)象會(huì)晉升到老年代?

  1. 如果新生代的垃圾收集器為Serial和ParNew,并且設(shè)置了-XX:PretenureSizeThreshold參數(shù),當(dāng)對(duì)象大于這個(gè)參數(shù)值時(shí),會(huì)被認(rèn)為是大對(duì)象,直接進(jìn)入老年代。
  2. Young GC后,如果對(duì)象太大無(wú)法進(jìn)入Survivor區(qū),則會(huì)通過(guò)分配擔(dān)保機(jī)制進(jìn)入老年代。
  3. 對(duì)象每在Survivor區(qū)中“熬過(guò)”一次Young GC,年齡就增加1歲,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲,可以通過(guò)-XX:MaxTenuringThreshold設(shè)置),就將會(huì)被晉升到老年代中。
  4. 如果在Survivor區(qū)中相同年齡所有對(duì)象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對(duì)象就可以直接進(jìn)入老年代,無(wú)須等到MaxTenuringThreshold中要求的年齡。

11.介紹下垃圾收集機(jī)制(在什么時(shí)候,對(duì)什么,做了什么)? 在什么時(shí)候?

在觸發(fā)GC的時(shí)候,具體如下,這里只說(shuō)常見(jiàn)的Young GC和Full GC。

觸發(fā)Young GC:當(dāng)新生代中的Eden區(qū)沒(méi)有足夠空間進(jìn)行分配時(shí)會(huì)觸發(fā)Young GC。

觸發(fā)Full GC:

  1. 當(dāng)準(zhǔn)備要觸發(fā)一次Young GC時(shí),如果發(fā)現(xiàn)統(tǒng)計(jì)數(shù)據(jù)說(shuō)之前Young GC的平均晉升大小比目前老年代剩余的空間大,則不會(huì)觸發(fā)Young GC而是轉(zhuǎn)為觸發(fā)Full GC。(通常情況)
  2. 如果有永久代的話(huà),在永久代需要分配空間但已經(jīng)沒(méi)有足夠空間時(shí),也要觸發(fā)一次Full GC。
  3. System.gc()默認(rèn)也是觸發(fā)Full GC。
  4. heap dump帶GC默認(rèn)也是觸發(fā)Full GC。
  5. 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開(kāi)始搜索,搜索不到的,并且經(jīng)過(guò)一次篩選標(biāo)記沒(méi)有復(fù)活的對(duì)象。

做了什么?

對(duì)這些JVM認(rèn)為已經(jīng)“死掉”的對(duì)象進(jìn)行垃圾收集,新生代使用復(fù)制算法,老年代使用標(biāo)記-清除和標(biāo)記-整理算法。

12.GC Root有哪些?

在Java語(yǔ)言中,可作為GC Roots的對(duì)象包括下面幾種:

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象。
  • 方法區(qū)中類(lèi)靜態(tài)屬性引用的對(duì)象。
  • 方法區(qū)中常量引用的對(duì)象。
  • 本地方法棧中JNI(即一般說(shuō)的Native方法)引用的對(duì)象。

13.發(fā)生Young GC的時(shí)候需要掃描老年代的對(duì)象嗎?

在分代收集中,新生代的規(guī)模一般都比老年代要小許多,新生代的收集也比老年代要頻繁許多,如果回收新生代時(shí)也不得不同時(shí)掃描老年代的話(huà),那么Young GC的效率可能下降不少。顯然是不可能區(qū)掃描老年代的,那么是通過(guò)什么辦法來(lái)解決這個(gè)問(wèn)題了?

在大多垃圾收集器中(G1有不同的地方),通過(guò)CardTable來(lái)維護(hù)老年代對(duì)年輕代的引用,CardTable可以說(shuō)是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))來(lái)標(biāo)識(shí)每個(gè)分區(qū)的空間地址。

14.垃圾收集器有哪些?

目前HotSpot中有7種作用于不同分代的收集器,如下圖所示,如果兩個(gè)收集器之間存在連線(xiàn),就說(shuō)明它們可以搭配使用。

15.介紹CMS垃圾收集器的特點(diǎn)?

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器。目前很大一部分的Java應(yīng)用集中在互聯(lián)網(wǎng)站或者B/S系統(tǒng)的服務(wù)端上,這類(lèi)應(yīng)用尤其重視服務(wù)的響應(yīng)速度,希望系統(tǒng)停頓時(shí)間最短,以給用戶(hù)帶來(lái)較好的體驗(yàn)。CMS收集器就非常符合這類(lèi)應(yīng)用的需求。

從名字(包含“Mark Sweep”)上就可以看出,CMS收集器是基于“標(biāo)記—清除”算法實(shí)現(xiàn)的,它的運(yùn)作過(guò)程可以分為6個(gè)步驟,包括:初始標(biāo)記、并發(fā)標(biāo)記、預(yù)處理、重新標(biāo)記、并發(fā)清除、重置。

CMS是一款優(yōu)秀的收集器,它的主要優(yōu)點(diǎn)在名字上已經(jīng)體現(xiàn)出來(lái)了:并發(fā)收集、低停頓,但是CMS還遠(yuǎn)達(dá)不到完美的程度,它有以下3個(gè)明顯的缺點(diǎn):

  1. CMS收集器對(duì)CPU資源非常敏感。
  2. CMS收集器無(wú)法處理浮動(dòng)垃圾(Floating Garbage),可能出現(xiàn)“Concurrent Mode Failure”失敗而導(dǎo)致另一次Full GC的產(chǎn)生。
  3. CMS是一款基于“標(biāo)記—清除”算法實(shí)現(xiàn)的收集器,這意味著收集結(jié)束時(shí)會(huì)有大量空間碎片產(chǎn)生。

16.介紹下G1垃圾收集器的特點(diǎn)?(較復(fù)雜,可以考慮跳過(guò))

G1(Garbage-First)收集器是當(dāng)今收集器技術(shù)發(fā)展的最前沿成果之一。G1是一款面向服務(wù)端應(yīng)用的垃圾收集器。與其他GC收集器相比,G1具備如下特點(diǎn):并行與并發(fā)、分代收集、空間整合、可預(yù)測(cè)的停頓。

在G1之前的其他收集器進(jìn)行收集的范圍都是整個(gè)新生代或者老年代,而G1不再是這樣。使用G1收集器時(shí),Java堆的內(nèi)存布局就與其他收集器有很大差別,它將整個(gè)Java堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域,雖然還保留有新生代和老年代的概念,但新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續(xù))的集合。

G1收集器之所以能建立可預(yù)測(cè)的停頓時(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名稱(chēng)的來(lái)由)。這種使用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.類(lèi)加載的過(guò)程。

類(lèi)從被加載到虛擬機(jī)內(nèi)存中開(kāi)始,到卸載出內(nèi)存為止,它的整個(gè)生命周期包括:加載、驗(yàn)證、準(zhǔn)備、解析、初始化、使用和卸載7個(gè)階段。其中驗(yàn)證、準(zhǔn)備、解析3個(gè)部分統(tǒng)稱(chēng)為連接。

加載:

“類(lèi)加載”過(guò)程的一個(gè)階段,在加載階段,虛擬機(jī)需要完成以下3件事情:

通過(guò)一個(gè)類(lèi)的全限定名來(lái)獲取定義此類(lèi)的二進(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è)類(lèi)的java.lang.Class對(duì)象,作為方法區(qū)這個(gè)類(lèi)的各種數(shù)據(jù)的訪(fǎng)問(wèn)入口。

驗(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)備:

該階段是正式為類(lèi)變量(static修飾的變量)分配內(nèi)存并設(shè)置類(lèi)變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。這里所說(shuō)的初始值“通常情況”下是數(shù)據(jù)類(lèi)型的零值,下表列出了Java中所有基本數(shù)據(jù)類(lèi)型的零值。

解析:

該階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程。

初始化:

初始化階段是執(zhí)行類(lèi)構(gòu)造器<clinit>()方法的過(guò)程。<clinit>()方法是由編譯器自動(dòng)收集類(lèi)中的所有類(lèi)變量(static修飾的變量)的賦值動(dòng)作和靜態(tài)語(yǔ)句塊(static{}塊)中的語(yǔ)句合并產(chǎn)生的,編譯器收集的順序是由語(yǔ)句在源文件中出現(xiàn)的順序所決定的。如果該類(lèi)存在父類(lèi),則虛擬機(jī)會(huì)保證在執(zhí)行子類(lèi)的<clinit>()方法前,父類(lèi)的<clinit>()方法已經(jīng)執(zhí)行完畢。因此在虛擬機(jī)中第一個(gè)被執(zhí)行<clinit>()方法的類(lèi)肯定是java.lang.Object。

18.Java虛擬機(jī)中有哪些類(lèi)加載器?

從Java虛擬機(jī)的角度來(lái)講,只存在兩種不同的類(lèi)加載器:一種是啟動(dòng)類(lèi)加載器(Bootstrap ClassLoader),這個(gè)類(lèi)加載器使用C++語(yǔ)言實(shí)現(xiàn),是虛擬機(jī)自身的一部分;另一種就是所有其他的類(lèi)加載器,這些類(lèi)加載器都由Java語(yǔ)言實(shí)現(xiàn),獨(dú)立于虛擬機(jī)外部,并且全都繼承自抽象類(lèi)java.lang.ClassLoader。

從Java開(kāi)發(fā)人員的角度來(lái)看,絕大部分Java程序都會(huì)使用到以下3種系統(tǒng)提供的類(lèi)加載器。

啟動(dòng)類(lèi)加載器(Bootstrap ClassLoader):

這個(gè)類(lèi)加載器負(fù)責(zé)將存放在<JAVA_HOME>\lib目錄中的,或者被-Xbootclasspath參數(shù)所指定的路徑中的,并且是虛擬機(jī)識(shí)別的(僅按照文件名識(shí)別,如rt.jar,名字不符合的類(lèi)庫(kù)即使放在lib目錄中也不會(huì)被加載)類(lèi)庫(kù)加載到虛擬機(jī)內(nèi)存中。

擴(kuò)展類(lèi)加載器(Extension ClassLoader):

這個(gè)加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),它負(fù)責(zé)加載<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類(lèi)庫(kù),開(kāi)發(fā)者可以直接使用擴(kuò)展類(lèi)加載器。

應(yīng)用程序類(lèi)加載器(Application ClassLoader):

這個(gè)類(lèi)加載器由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。由于這個(gè)類(lèi)加載器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也稱(chēng)它為系統(tǒng)類(lèi)加載器。它負(fù)責(zé)加載用戶(hù)類(lèi)路徑(ClassPath)上所指定的類(lèi)庫(kù),開(kāi)發(fā)者可以直接使用這個(gè)類(lèi)加載器,如果應(yīng)用程序中沒(méi)有自定義過(guò)自己的類(lèi)加載器,一般情況下這個(gè)就是程序中默認(rèn)的類(lèi)加載器。

我們的應(yīng)用程序都是由這3種類(lèi)加載器互相配合進(jìn)行加載的,如果有必要,還可以加入自己定義的類(lèi)加載器。這些類(lèi)加載器之間的關(guān)系一般如圖所示。

19.什么是雙親委派模型?

如果一個(gè)類(lèi)加載器收到了類(lèi)加載的請(qǐng)求,它首先不會(huì)自己去嘗試加載這個(gè)類(lèi),而是把這個(gè)請(qǐng)求委派給父類(lèi)加載器去完成,每一個(gè)層次的類(lèi)加載器都是如此,因此所有的加載請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類(lèi)加載器中,只有當(dāng)父加載器反饋?zhàn)约簾o(wú)法完成這個(gè)加載請(qǐng)求(它的搜索范圍中沒(méi)有找到所需的類(lèi))時(shí),子加載器才會(huì)嘗試自己去加載。

20.使用雙親委派模型的好處?

使用雙親委派模型來(lái)組織類(lèi)加載器之間的關(guān)系,有一個(gè)顯而易見(jiàn)的好處就是Java類(lèi)隨著它的類(lèi)加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系。例如類(lèi)java.lang.Object,它存放在rt.jar之中,無(wú)論哪一個(gè)類(lèi)加載器要加載這個(gè)類(lèi),最終都是委派給處于模型最頂端的啟動(dòng)類(lèi)加載器進(jìn)行加載,因此Object類(lèi)在程序的各種類(lèi)加載器環(huán)境中都是同一個(gè)類(lèi)。相反,如果沒(méi)有使用雙親委派模型,由各個(gè)類(lèi)加載器自行去加載的話(huà),如果用戶(hù)自己編寫(xiě)了一個(gè)稱(chēng)為java.lang.Object的類(lèi),并放在程序的ClassPath中,那系統(tǒng)中將會(huì)出現(xiàn)多個(gè)不同的Object類(lèi),Java 類(lèi)型體系中最基礎(chǔ)的行為也就無(wú)法保證,應(yīng)用程序也將會(huì)變得一片混亂。

總結(jié)

這篇JAVA虛擬機(jī)·面試題的總結(jié)就到這了,希望大家可以多多關(guān)注腳本之家的其他精彩文章!

相關(guān)文章

  • java操作mongodb時(shí),對(duì)象bean和DBObject相互轉(zhuǎn)換的方法(推薦)

    java操作mongodb時(shí),對(duì)象bean和DBObject相互轉(zhuǎn)換的方法(推薦)

    下面小編就為大家?guī)?lái)一篇java操作mongodb時(shí),對(duì)象bean和DBObject相互轉(zhuǎn)換的方法(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11
  • 教你bat腳本一鍵配置java開(kāi)發(fā)環(huán)境

    教你bat腳本一鍵配置java開(kāi)發(fā)環(huán)境

    公司新入職一名員工,項(xiàng)目經(jīng)理讓我安排新人工作,首先需要對(duì)java開(kāi)發(fā)相關(guān)環(huán)境進(jìn)行配置安裝,但時(shí)常會(huì)因?yàn)榘惭b配置不到位或者操作錯(cuò)誤導(dǎo)致時(shí)間的浪費(fèi),所以在空余時(shí)間收集了一系列軟件的免安裝版本,感興趣的朋友一起看看吧
    2021-12-12
  • SpringBoot使用swagger生成api接口文檔的方法詳解

    SpringBoot使用swagger生成api接口文檔的方法詳解

    在之前的文章中,使用mybatis-plus生成了對(duì)應(yīng)的包,在此基礎(chǔ)上,我們針對(duì)項(xiàng)目的api接口,添加swagger配置和注解,生成swagger接口文檔,需要的可以了解一下
    2022-10-10
  • 5種解決Java獨(dú)占寫(xiě)文件的方法

    5種解決Java獨(dú)占寫(xiě)文件的方法

    這篇文章主要介紹了5種解決Java獨(dú)占寫(xiě)文件的方法,需要的朋友可以參考下
    2015-12-12
  • 解決Servlet4.0版本使用注解設(shè)置url但無(wú)法訪(fǎng)問(wèn)的問(wèn)題

    解決Servlet4.0版本使用注解設(shè)置url但無(wú)法訪(fǎng)問(wèn)的問(wèn)題

    在學(xué)習(xí)servlet過(guò)程中,使用web.xml文件配置servlet可以正常訪(fǎng)問(wèn),但使用WebServlet注解時(shí)出現(xiàn)404錯(cuò)誤,解決方法是在web.xml文件中將metadata-complete屬性改為false,啟動(dòng)標(biāo)注支持,然而該方法對(duì)我無(wú)效,最后通過(guò)重建項(xiàng)目和手動(dòng)將新建的項(xiàng)目添加到tomcat服務(wù)器解決問(wèn)題
    2024-10-10
  • Java實(shí)現(xiàn)在線(xiàn)編輯預(yù)覽office文檔詳解

    Java實(shí)現(xiàn)在線(xiàn)編輯預(yù)覽office文檔詳解

    PageOffice是一款在線(xiàn)的office編輯軟件,幫助Web應(yīng)用系統(tǒng)或Web網(wǎng)站實(shí)現(xiàn)用戶(hù)在線(xiàn)編輯Word、Excel、PowerPoint文檔,下面我們就來(lái)看看如何使用Java實(shí)現(xiàn)在線(xiàn)預(yù)覽office吧
    2024-01-01
  • request如何獲取完整url(包括域名、端口、參數(shù))

    request如何獲取完整url(包括域名、端口、參數(shù))

    這篇文章主要介紹了request如何獲取完整url(包括域名、端口、參數(shù))問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • springboot如何添加task任務(wù)執(zhí)行隊(duì)列

    springboot如何添加task任務(wù)執(zhí)行隊(duì)列

    這篇文章主要介紹了springboot如何添加task任務(wù)執(zhí)行隊(duì)列問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java數(shù)組擴(kuò)容實(shí)現(xiàn)方法解析

    Java數(shù)組擴(kuò)容實(shí)現(xiàn)方法解析

    這篇文章主要介紹了Java數(shù)組擴(kuò)容實(shí)現(xiàn)方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Java實(shí)現(xiàn)合并兩個(gè)有序序列算法示例

    Java實(shí)現(xiàn)合并兩個(gè)有序序列算法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)合并兩個(gè)有序序列算法,簡(jiǎn)單描述了序列合并算法的原理與java合并有序序列的具體操作步驟及相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-09-09

最新評(píng)論