阿里、美团、Oracle凭这套题不知道刷了多少人
一、為什么Java被稱作是“平臺(tái)無關(guān)的編程語言”?
程序員所需要的知識(shí)體系
前言
有代碼的地方,就有江湖。
程序員,就是“一人,一鍵,二機(jī)”行走其間的孤獨(dú)劍客。在江湖中狂蕩,必然要練就絕世武功,則需要內(nèi)外兼?zhèn)?#xff1a; 精妙的招式,加之深厚的內(nèi)功。 武功的基礎(chǔ)是內(nèi)功,一個(gè)內(nèi)功低的人招式再奇妙,也打不過一個(gè)內(nèi)功深厚之人。同樣兩者也是相輔相成,內(nèi)功深厚,原來的一招一式威力也會(huì)倍增。
對于開發(fā)者來說,其道理也是一樣。 流行的框架越來越多,封裝也越來越完善,各種框架可以搞定一切。
初級(jí)程序員只要熟悉基本的使用方法,幾乎不用關(guān)注底層的實(shí)現(xiàn),便可以快速地開發(fā)上線。
但對于想要進(jìn)階的你來說,更要注重內(nèi)功,比如算法、設(shè)計(jì)模式、底層原理等等。 只有把基礎(chǔ)打扎實(shí),才能知其然知其所以然,出現(xiàn)Bug能快速發(fā)現(xiàn)問題本質(zhì)。
作者鄭雨迪在Java虛擬機(jī)性能優(yōu)化方面有著多年的研究,深知JVM是內(nèi)功心法很重要的一塊。上線出現(xiàn)性能問題,JVM調(diào)優(yōu)更是不可回避的事情。但又因Java虛擬機(jī)封裝得太好,讓我們幾乎感覺不到它的存在,可 學(xué)習(xí)Java虛擬機(jī)對于高級(jí)程序員來說,其重要性是不言而喻的。
我司在面試高級(jí)開發(fā)的時(shí)候,JVM相關(guān)知識(shí)也必定是考核的標(biāo)準(zhǔn)之一。
下面這篇文章集錦了阿里、美團(tuán)、Oracle等大廠的JVM考點(diǎn),你看看是否會(huì)能答得上來?
根據(jù)鄭雨迪專欄《深入拆解Java虛擬機(jī)》的內(nèi)容,我挑選了幾個(gè)問題進(jìn)行解答,希望能對大家面試起到幫助。
1、Java代碼是怎么運(yùn)行的?
這個(gè)問題可以分三塊來回答:
- 為什么Java要在虛擬機(jī)里運(yùn)行?
- Java虛擬機(jī)具體是怎樣運(yùn)行Java字節(jié)碼的?
- Java虛擬機(jī)的運(yùn)行效率究竟是怎么樣的?
Java之所以要在虛擬機(jī)中運(yùn)行,是因?yàn)樗峁┝丝梢浦残浴R坏㎎ava代碼被編譯為Java字節(jié)碼,便可以在不同平臺(tái)上的Java虛擬機(jī)實(shí)現(xiàn)上運(yùn)行。此外,虛擬機(jī)還提供了一個(gè)代碼托管的環(huán)境,代替我們處理部分冗長而且容易出錯(cuò)的事務(wù),例如內(nèi)存管理。
Java虛擬機(jī)將運(yùn)行時(shí)內(nèi)存區(qū)域劃分為五個(gè)部分,分別為方法區(qū)、堆、PC寄存器、Java方法棧和本地方法棧。Java程序編譯而成的class文件,需要先加載至方法區(qū)中,方能在Java虛擬機(jī)中運(yùn)行。
為了提高運(yùn)行效率,標(biāo)準(zhǔn)JDK中的HotSpot虛擬機(jī)采用的是一種混合執(zhí)行的策略。首先,它會(huì)解釋執(zhí)行Java字節(jié)碼,然后會(huì)將其中反復(fù)執(zhí)行的熱點(diǎn)代碼,以方法為單位進(jìn)行即時(shí)編譯,翻譯成機(jī)器碼后直接運(yùn)行在底層硬件之上。HotSpot裝載了多個(gè)不同的即時(shí)編譯器,以便在編譯時(shí)間和生成代碼的執(zhí)行效率之間做取舍。
2、Java虛擬機(jī)是如何加載Java類的?
Java虛擬機(jī)將字節(jié)流轉(zhuǎn)化為Java類的過程,可分為加載、鏈接以及初始化三大步驟。也可以用蓋房子來類比Java虛擬機(jī)中的類加載。
- 加載是指查找字節(jié)流,并且據(jù)此創(chuàng)建類的過程。 以蓋房子為例,村里的Tony要蓋個(gè)房子,那么按照流程他得先找個(gè)建筑師,跟他說想要設(shè)計(jì)一個(gè)房型,比如說“一房、一廳、四衛(wèi)”。這里的房型相當(dāng)于類,而建筑師,就相當(dāng)于類加載器。村里有許多建筑師,他們等級(jí)森嚴(yán),但有著共同的祖師爺,叫啟動(dòng)類加載器(boot class loader)。
加載需要借助類加載器,在Java虛擬機(jī)中,類加載器使用了雙親委派模型,即接收到加載請求時(shí),會(huì)先將請求轉(zhuǎn)發(fā)給父類加載器。
- 鏈接,是指將創(chuàng)建成的類合并至Java虛擬機(jī)中,使之能夠執(zhí)行的過程。 鏈接還分驗(yàn)證、準(zhǔn)備和解析三個(gè)階段。其中,解析階段為非必須的。
- 初始化,則是為標(biāo)記為常量值的字段賦值,以及執(zhí)行 <clinit> 方法的過程。 類的初始化僅會(huì)被執(zhí)行一次,這個(gè)特性被用來實(shí)現(xiàn)單例的延遲初始化。這放在我們蓋房子的例子中就是,只有當(dāng)房子裝修過后,Tony才能真正地住進(jìn)去。
3、異常捕獲是如何實(shí)現(xiàn)的?
在編譯生成的Java字節(jié)碼中,每個(gè)方法都附帶一個(gè)異常表。異常表中的每一行均定義了一條異常執(zhí)行路徑,其中包括規(guī)定捕獲范圍的起始字節(jié)碼索引、終止(不包含)字節(jié)碼索引,異常處理代碼的起始字節(jié)碼索引,以及所捕獲的異常類型。
當(dāng)程序觸發(fā)異常時(shí),JVM會(huì)從上至下遍歷異常表中的所有條目。當(dāng)觸發(fā)異常的字節(jié)碼的索引值在某行異常表?xiàng)l目的捕獲范圍內(nèi),JVM會(huì)判斷所拋出的異常和該條目想要捕獲的異常是否匹配。如果匹配,JVM會(huì)將控制流轉(zhuǎn)移至該條目所指向的異常處理代碼。
上述異常捕獲機(jī)制還被用于finally從句的實(shí)現(xiàn)。通常,Java程序的編譯器javac會(huì)復(fù)制多份finally代碼塊,放置于生成的Java字節(jié)碼之中,然后通過生成多行異常表?xiàng)l目,來實(shí)現(xiàn)完整的finally邏輯。
4、垃圾回收的基礎(chǔ)思想是什么?
目前JVM的主流垃圾回收器采取的都是可達(dá)性分析算法 。該算法的實(shí)質(zhì)是將一系列被稱為GC Roots的對象作為初始的存活對象合集,然后從該合集出發(fā)探索所有能夠被該集合引用到的對象,并 標(biāo)記 為存活對象。當(dāng)標(biāo)記階段結(jié)束之后,未被標(biāo)記到的對象便是可以 清除 的。
傳統(tǒng)的垃圾回收算法在標(biāo)記、清除過程中需要中止其他應(yīng)用線程,即所謂的Stop-The-World。新型的垃圾回收算法,如CMS、G1以及ZGC,盡可能地實(shí)現(xiàn) 并發(fā) 標(biāo)記、清除,從而讓Stop-The-World的時(shí)間長度可控。
垃圾回收的另一基礎(chǔ)思想則是 分代回收 。 JVM會(huì)將新生成的對象劃為新生代,而將在多次垃圾回收中存活下來的對象劃為老年代。JVM會(huì)為不同的分代設(shè)置不同的回收算法,從而達(dá)到新生代多收集、快收集,老年代少收集、全收集的目標(biāo)。
5、JVM垃圾回收算法
- 標(biāo)記-清除算法: 首先標(biāo)記出所有需要回收的對象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對象。
- 復(fù)制算法: 將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)一塊內(nèi)存用完了,將還存另外一塊上面,然后在把已使用過的內(nèi)存空間一次清理掉。
- 標(biāo)記-整理算法: 標(biāo)記過程與“標(biāo)記-清除”算法一樣,但后續(xù)步驟不是直接對可回收對象進(jìn)行清理,而是讓所一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。
- 分代收集算法: 一般是把Java堆分為新生代和老年代,根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴āP律及l(fā)現(xiàn)有大批對象死去,選用復(fù)制算法。老年代中因?yàn)閷ο蟠婊盥矢?#xff0c;必須使用“標(biāo)記-清理”或“標(biāo)記-整理”算法來進(jìn)行回收。
轉(zhuǎn)載于:https://juejin.im/post/5d05eae26fb9a07ef56234cb
總結(jié)
以上是生活随笔為你收集整理的阿里、美团、Oracle凭这套题不知道刷了多少人的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无线局域网的部署
- 下一篇: 爬取百度文库内容(Selenium+Be