您好,登錄后才能下訂單哦!
概述:知識(shí)點(diǎn)匯總
jvm的知識(shí)點(diǎn)匯總共6個(gè)大方向:內(nèi)存模型、類(lèi)加載機(jī)制、GC垃圾回收是比較重點(diǎn)的內(nèi)容。性能調(diào)優(yōu)部分偏重實(shí)際應(yīng)用,重點(diǎn)突出實(shí)踐能力。編譯器優(yōu)化和執(zhí)行模式部分偏重理論基礎(chǔ),主要掌握知識(shí)點(diǎn)。
各個(gè)部分的內(nèi)容如下:
1>內(nèi)存模型部分:程序計(jì)數(shù)器、方法區(qū)、堆、棧、本地方法棧的作用,保存哪些數(shù)據(jù);
2>類(lèi)加載部分:雙親委派的加載機(jī)制以及常用類(lèi)加載器分別加載哪種類(lèi)型的類(lèi);
3>GC部分:分代回收的思想和依據(jù),以及不同垃圾回收算法實(shí)現(xiàn)的思路、適合的場(chǎng)景;
4>性能調(diào)優(yōu)部分:常用的jvm優(yōu)化參數(shù)的作用,參數(shù)調(diào)優(yōu)的依據(jù),要了解常用的jvm分析工具能分析哪類(lèi)問(wèn)題,以及使用方法;
5>執(zhí)行模式部分:解釋、編譯、混合模式的優(yōu)缺點(diǎn),了解java7提供的分層編譯技術(shù)。需要知道JIT即時(shí)編譯技術(shù)和OSR也就是棧上替換,知道C1、C2編譯器針對(duì)的場(chǎng)景,其中C2針對(duì)server模式,優(yōu)化更激進(jìn)。在新技術(shù)方面可以了解一下java10提供的由java實(shí)現(xiàn)的graal編譯器。
6>編譯優(yōu)化部分:前端編譯器javac的編譯過(guò)程、AST抽象語(yǔ)法樹(shù)、編譯期優(yōu)化和運(yùn)行期優(yōu)化。編譯優(yōu)化的常用技術(shù),包括公共子表達(dá)式的消除、方法內(nèi)聯(lián)、逃逸分析、棧上分配、同步消除等。明白了這些才能寫(xiě)出對(duì)編譯器友好的代碼。
jvm的內(nèi)容相對(duì)來(lái)說(shuō)比較集中,但是對(duì)知識(shí)深度的掌握要求較高,建議面試前重點(diǎn)加強(qiáng)。
1.詳解-jvm內(nèi)存模型?
jvm內(nèi)存模型主要指運(yùn)行時(shí)的數(shù)據(jù)區(qū),包括5個(gè)部分。
棧也叫方法棧,是線(xiàn)程私有的,線(xiàn)程在執(zhí)行每個(gè)方法時(shí)都會(huì)同時(shí)創(chuàng)建一個(gè)棧幀,用來(lái)存儲(chǔ)局部變量表、操作棧、動(dòng)態(tài)鏈接、方法出口等信息。調(diào)用方法時(shí)執(zhí)行入棧,方法返回時(shí)執(zhí)行出棧。
本地方法棧與棧類(lèi)似,也是用來(lái)保存線(xiàn)程執(zhí)行方法時(shí)的信息,不同的是,執(zhí)行java方法使用棧,而執(zhí)行native方法使用本地方法棧。
程序計(jì)數(shù)器保存著當(dāng)前線(xiàn)程所執(zhí)行的字節(jié)碼位置,每個(gè)線(xiàn)程工作時(shí)都有一個(gè)獨(dú)立的計(jì)數(shù)器。程序計(jì)數(shù)器為執(zhí)行java方法服務(wù),執(zhí)行native方法時(shí),程序計(jì)數(shù)器為空。
棧、本地方法棧、程序計(jì)數(shù)器這三個(gè)部分都是線(xiàn)程獨(dú)占的。
堆是jvm管理的內(nèi)存中最大的一塊,堆被所有線(xiàn)程共享,目的是為了存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配。當(dāng)堆內(nèi)存沒(méi)有可用的空間時(shí),會(huì)拋出OOM異常。根據(jù)對(duì)象存活的周期不同,jvm把堆內(nèi)存進(jìn)行分代管理,由垃圾回收器來(lái)進(jìn)行對(duì)象的回收管理。
方法區(qū)也是各個(gè)線(xiàn)程共享的內(nèi)存區(qū)域,又叫非堆區(qū)。用于存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù),
jdk1.7中的永久代和1.8中的metaspace都是方法區(qū)的一種實(shí)現(xiàn)。
面試回答此知識(shí)點(diǎn)相關(guān)問(wèn)題時(shí),要答出兩個(gè)要點(diǎn):一個(gè)是各部分的功能,另一個(gè)是哪些線(xiàn)程共享,哪些獨(dú)占。
2.詳解-jmm內(nèi)存可見(jiàn)性? ? ?
jmm是java內(nèi)存模型,與剛才講到的jvm內(nèi)存模型是兩回事,jmm的主要目標(biāo)是定義程序中變量的訪(fǎng)問(wèn)規(guī)則,如圖所示,所有的共享變量都存儲(chǔ)在主內(nèi)存中共享。每個(gè)線(xiàn)程有自己的工作內(nèi)存,工作內(nèi)存中保存的是主內(nèi)存中變量的副本,線(xiàn)程對(duì)變量的讀寫(xiě)等操作必須在自己 的工作內(nèi)存中進(jìn)行,而不能直接讀寫(xiě)主內(nèi)存中的變量。
在多線(xiàn)程進(jìn)行數(shù)據(jù)交互時(shí),例如線(xiàn)程a給一個(gè)共享變量賦值后,由線(xiàn)程b來(lái)讀取這個(gè)值,a修改完變量是修改在自己的工作區(qū)內(nèi)存中,b是不可見(jiàn)的,只有從a的工作區(qū)寫(xiě)回到主內(nèi)存,b再?gòu)闹鲀?nèi)存讀取到自己的工作區(qū)才能進(jìn)行進(jìn)一步的操作。由于指令重排序的存在,這個(gè)寫(xiě)-讀的順序有可能被打亂。
因此jmm需要提供原子性、可見(jiàn)性、有序性的保證。
3、詳解-jmm保證
主要介紹下jmm如何保證原子性、可見(jiàn)性,有序性。
jmm保證對(duì)除long和double外的基礎(chǔ)數(shù)據(jù)類(lèi)型的讀寫(xiě)操作是原子性的。另外關(guān)鍵字Synchronized也可以提供原子性保證。Synchronized的原子性是通過(guò)java的兩個(gè)高級(jí)的字節(jié)碼指令monitorenter和monitorexit來(lái)保證的。
jmm可見(jiàn)性的保證,一個(gè)是通過(guò)Synchronized,另外一個(gè)就是volatile。volatile強(qiáng)制變量的賦值會(huì)同步刷新回主內(nèi)存,強(qiáng)制變量的讀取會(huì)從主內(nèi)存重新加載,保證不同的線(xiàn)程總是能夠看到該變量的最新值。
jmm對(duì)有序性的保證,主要通過(guò)volatile和一系列happens-before原則。volatile的另一個(gè)作用就是阻止指令重排序,這樣就可以保證變量讀寫(xiě)的有序性。
happens-before原則包括一系列規(guī)則,如
程序順序原則,即一個(gè)線(xiàn)程內(nèi)必須保證語(yǔ)義串行性;
鎖規(guī)則,即對(duì)同一個(gè)鎖的解鎖一定發(fā)生在再次加鎖之前;
1.詳解類(lèi)加載機(jī)制? ? ?
類(lèi)的加載指的是將編譯好的class類(lèi)文件中的字節(jié)碼讀入到內(nèi)存中,將其放在方法區(qū)內(nèi)并創(chuàng)建對(duì)應(yīng)的Class對(duì)象。
類(lèi)的加載分為加載、鏈接、初始化,其中鏈接又包括驗(yàn)證、準(zhǔn)備、解析三步??吹綀D中上半部分深綠色,我們逐個(gè)分析:
加載是文件到內(nèi)存的過(guò)程。通過(guò)類(lèi)的完全限定名查找此類(lèi)字節(jié)碼文件,并利用字節(jié)碼文件創(chuàng)建一個(gè)Class對(duì)象
驗(yàn)證是對(duì)類(lèi)文件內(nèi)容驗(yàn)證。目的在于確保Class文件符合當(dāng)前虛擬機(jī)要求,不會(huì)危害虛擬機(jī)自身安全。主要包括四種:文件格式驗(yàn)證,元數(shù)據(jù)驗(yàn)證,字節(jié)碼驗(yàn)證,符號(hào)引用驗(yàn)證。
準(zhǔn)備階段是進(jìn)行內(nèi)存分配。為類(lèi)變量也就是類(lèi)中由static修飾的變量分配內(nèi)存,并且設(shè)置初始值,這里要注意,初始值是0或者null,而不是代碼中設(shè)置的具體值,代碼中設(shè)置的值是在初始化階段完成的。另外這里也不包含用final修飾的靜態(tài)變量,因?yàn)閒inal在編譯的時(shí)候就會(huì)分配了。
解析主要是解析字段、接口、方法。主要是將常量池中的符號(hào)引用替換為直接引用的過(guò)程。直接引用就是直接指向目標(biāo)的指針、相對(duì)偏移量等。
只有對(duì)類(lèi)主動(dòng)使用時(shí),才會(huì)進(jìn)行初始化,初始化的觸發(fā)條件包括創(chuàng)建類(lèi)的實(shí)例的時(shí)候、訪(fǎng)問(wèn)類(lèi)的靜態(tài)方法或者靜態(tài)變量的時(shí)候、Class.forName()反射類(lèi)的時(shí)候、或者某個(gè)子類(lèi)被初始化的時(shí)候。
類(lèi)的生命周期,就是從類(lèi)的加載到類(lèi)實(shí)例的創(chuàng)建與使用,再到類(lèi)對(duì)象不再被使用時(shí)可以被GC卸載回收。這里要注意一點(diǎn),由java虛擬機(jī)自帶的三種類(lèi)加載器加載的類(lèi)在虛擬機(jī)的整個(gè)生命周期中是不會(huì)被卸載的,只有用戶(hù)自定義的類(lèi)加載器所加載的類(lèi)才可以被卸載。
2.詳解類(lèi)加載器? ??
java自帶的三種類(lèi)加載器分別是:bootstrap啟動(dòng)類(lèi)加載器、擴(kuò)展類(lèi)加載器和應(yīng)用加載器也叫系統(tǒng)加載器。圖右邊的桔×××文字表示各類(lèi)加載器對(duì)應(yīng)的加載目錄。啟動(dòng)類(lèi)加載器加載java home中l(wèi)ib目錄下的類(lèi),擴(kuò)展加載器負(fù)責(zé)加載ext目錄下的類(lèi),應(yīng)用加載器加載classpath指定目錄下的類(lèi)。
除此之外,可以自定義類(lèi)加載器。
java的類(lèi)加載使用雙親委派模式,即一個(gè)類(lèi)加載器在加載類(lèi)時(shí),先把這個(gè)請(qǐng)求委托給自己的父類(lèi)加載器去執(zhí)行,如果父類(lèi)加載器還存在父類(lèi)加載器,就繼續(xù)向上委托,直到頂層的啟動(dòng)類(lèi)加載器,如圖中藍(lán)色向上的箭頭。如果父類(lèi)加載器能夠完成類(lèi)加載,就成功返回,如果父類(lèi)加載器無(wú)法完成加載,那么子加載器才會(huì)嘗試自己去加載。
這種雙親委派模式的好處,一個(gè)可以避免類(lèi)的重復(fù)加載,另外也避免了java的核心API被篡改。
1.詳解分代回收? ???
前面提到過(guò),java的堆內(nèi)存被分代管理,分代管理主要是為了方便垃圾回收,這樣做基于2個(gè)事實(shí),第一、大部分對(duì)象很快就不再使用,第二,還有一部分不會(huì)立即無(wú)用,但也不會(huì)持續(xù)很長(zhǎng)時(shí)間。
虛擬機(jī)中劃分為年輕代、老年代、和永久代。
1>年輕代:主要用來(lái)存放新創(chuàng)建的對(duì)象,年輕代分為eden區(qū)和兩個(gè)Survivor區(qū)。大部分對(duì)象在Eden區(qū)中生成。當(dāng)Eden區(qū)滿(mǎn)時(shí),還存活的對(duì)象會(huì)在兩個(gè)Survivor區(qū)交替保存,達(dá)到一定次數(shù)的對(duì)象會(huì)晉升到老年代。
2>老年代:用來(lái)存放從年輕代晉升而來(lái)的,存活時(shí)間較長(zhǎng)的對(duì)象。
3>永久代:主要保存類(lèi)信息等內(nèi)容,這里的永久代是指對(duì)象劃分方式,不是專(zhuān)指1.7的permGen,或者1.8之后的metaspace。
根據(jù)年輕代與老年代的特點(diǎn),jvm提供了不同的垃圾回收算法。垃圾回收算法按類(lèi)型可以分為引用計(jì)數(shù)法、復(fù)制法和標(biāo)記清除法。
其中引用計(jì)數(shù)法是通過(guò)對(duì)象被引用的次數(shù)來(lái)確定對(duì)象是否被使用,缺點(diǎn)是無(wú)法解決循環(huán)引用的問(wèn)題。
復(fù)制算法需要from和to兩塊相同大小的內(nèi)存空間,對(duì)象分配時(shí)只在from塊中進(jìn)行,回收時(shí)把存活對(duì)象復(fù)制到to塊中,并清空f(shuō)rom塊,然后交換兩塊的分工,即把from塊作為to塊,把to塊作為from塊。缺點(diǎn)是內(nèi)存使用率較低。
標(biāo)記清除算法分為標(biāo)記對(duì)象和清除不在使用的對(duì)象兩個(gè)階段,標(biāo)記清除算法的缺點(diǎn)是會(huì)產(chǎn)生內(nèi)存碎片。
jvm中提供的年輕代回收算法Serial、ParNew、Parallel Scavenge都是復(fù)制算法,而CMS、G1、zgc都屬于標(biāo)記清除算法。
本篇文章,對(duì)這幾個(gè)算法就不展開(kāi)了
?
總結(jié):面試考察點(diǎn)及加分項(xiàng)
1.jvm相關(guān)的面試考察點(diǎn)
首先,需要jvm的內(nèi)存模型和java的內(nèi)存模型;
其次,要了解的類(lèi)的加載過(guò)程,了解雙親委派機(jī)制;
第三,要理解內(nèi)存的可見(jiàn)性與java內(nèi)存模型對(duì)原子性、可見(jiàn)性、有序性的保證機(jī)制;
第四,要了解常用的gc算法的特點(diǎn)、執(zhí)行過(guò)程,和適用場(chǎng)景,例如g1適合對(duì)最大延遲有要求的場(chǎng)合,zgc適用于64為系統(tǒng)的大內(nèi)存服務(wù)中;
第五,要了解常用的jvm參數(shù),明白對(duì)不同參數(shù)的調(diào)整會(huì)有怎樣的影響,適用什么樣的場(chǎng)景。例如垃圾回收的并發(fā)數(shù)、偏向鎖設(shè)置等
2.相關(guān)加分項(xiàng)
如果想要面試官對(duì)你留下更好的印象的話(huà),注意這些加分項(xiàng):?
首先,如果在編譯器優(yōu)化方面有深入的了解的話(huà),會(huì)讓面試官覺(jué)得你對(duì)技術(shù)的深度比較有追求。例如知道在編程時(shí)如何合理利用棧上分配降低gc壓力、如何編寫(xiě)適合內(nèi)聯(lián)優(yōu)化等代碼等。
其次,如果你能有線(xiàn)上實(shí)際問(wèn)題的排查經(jīng)驗(yàn)或思路那就更好了,面試官都喜歡動(dòng)手能力強(qiáng)的同學(xué)。例如解決過(guò)線(xiàn)上經(jīng)常full gc問(wèn)題,排查過(guò)內(nèi)存泄露問(wèn)題等。
第三,如果能有針對(duì)特定場(chǎng)景的jvm優(yōu)化實(shí)踐或者優(yōu)化思路,也會(huì)有意想不到的效果。例如針對(duì)高并發(fā)低延遲的場(chǎng)景,如何調(diào)整gc參數(shù)盡量降低gc停頓時(shí)間,針對(duì)隊(duì)列處理機(jī)如何盡可能提高吞吐率等;
總之,掌握以上具體的JVM考點(diǎn),才能在面試時(shí)應(yīng)答自如。希望讀完此篇文章的你,能做好準(zhǔn)備,拿到心儀的Offer。
針對(duì)于上面所涉及到的知識(shí)點(diǎn)我總結(jié)出了有1到5年開(kāi)發(fā)經(jīng)驗(yàn)的程序員在面試中涉及到的絕大部分架構(gòu)面試題及答案做成了文檔和架構(gòu)視頻資料免費(fèi)分享給大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并發(fā)等架構(gòu)技術(shù)資料),希望能幫助到您面試前的復(fù)習(xí)且找到一個(gè)好的工作,也節(jié)省大家在網(wǎng)上搜索資料的時(shí)間來(lái)學(xué)習(xí),也可以關(guān)注我一下以后會(huì)有更多干貨分享。
免責(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)容。