1. 程式人生 > >阿里、美團、Oracle等大廠的Java虛擬機器面試題集錦

阿里、美團、Oracle等大廠的Java虛擬機器面試題集錦

“有程式碼的地方,就有江湖。”

 

程式設計師,就是“一人,一鍵,二機”行走其間的孤獨劍客。我們遊走程式碼江湖,彈指間,便可掀起一場風雨變革。而在江湖中狂蕩,必然要練就絕世武功,則需要內外兼備:精妙的招式,加之深厚的內功。武功的基礎是內功,一個內功低的人招式再奇妙,也打不過一個內功深厚之人。同樣兩者也是相輔相成,內功深厚,原來的一招一式威力也會倍增。

 

對於開發者來說,其道理也是一樣。流行的框架越來越多,封裝也越來越完善,各種框架可以搞定一切。初級程式設計師只要熟悉基本的使用方法,幾乎不用關注底層的實現,便可以快速地開發上線。但對於想要進階的你來說,更要注重內功,比如演算法、設計模式、底層原理等等。只有把基礎打紮實,才能知其然知其所以然,出現Bug能快速發現問題本質。

 

我在Java虛擬機器效能優化方面有著多年的研究,深知Spring全家桶是精妙的招式,JVM就是內功心法很重要的一塊。線上出現效能問題,JVM調優更是不可迴避的問題。但又因Java虛擬機器封裝得太好,讓我們幾乎感覺不到它的存在,可學習Java虛擬機器對於高階程式設計師來說,其重要性是不言而喻的。我司在面試高階開發的時候,JVM相關知識也必定是考核的標準之一。

 

下面這篇文章集錦了阿里、美團、Oracle等大廠的JVM考點,你看看是否會能答得上來?

 

  1. 什麼是Java虛擬機器?為什麼Java被稱作是“平臺無關的程式語言”?

  2. Java程式碼是怎麼執行的?

  3. Java虛擬機器是如何載入Java類的?

  4. JVM執行記憶體的分類

  5. 如何監控和診斷JVM堆內和堆外記憶體使用?

  6. Java四引用是什麼?

  7. 如何理解JVM內建的編譯或GC日誌?

  8. JVM的永久代中會發生垃圾回收麼?

  9. Java中的兩種異常型別是什麼?他們有什麼區別?

  10. JVM是如何實現同步的?

  11. Java內在模型是什麼?

  12. 即使編譯器有哪些優化?

  13. 在什麼情況下重複讀寫操作會被優化?

  14. 什麼樣的垃圾才被回收?

  15. 什麼時候會導致垃圾回收?

  16. 如何利用JFR和JMC監控Java程式?

  17. 如何利用Unsafe API 繞開 JVM的控制?

  18. 如何利用位元組碼注入為已有程式碼加料?

……

根據我專欄的內容,我挑選了幾個問題進行解答,希望能對大家面試起到幫助。

1、什麼是Java虛擬機器?為什麼Java被稱作是“平臺無關的程式語言”?

 

Java虛擬機器是一個可以執行Java位元組碼的虛擬機器程序。Java原始檔被編譯成能被Java虛擬機器執行的位元組碼檔案。

 

Java被設計成允許應用程式可以執行在任意的平臺,而不需要程式設計師為每一個平臺單獨重寫或者是重新編譯。Java虛擬機器讓這個變為可能,因為它知道底層硬體平臺的指令長度和其他特性。

 

2、Java程式碼是怎麼執行的?

 

這個問題可以分三塊來回答:

  1. 為什麼Java要在虛擬機器裡執行?

  2. Java虛擬機器具體是怎樣執行Java位元組碼的?

  3. Java虛擬機器的執行效率究竟是怎麼樣的?

 

Java之所以要在虛擬機器中執行,是因為它提供了可移植性。一旦Java程式碼被編譯為Java位元組碼,便可以在不同平臺上的Java虛擬機器實現上執行。此外,虛擬機器還提供了一個程式碼託管的環境,代替我們處理部分冗長而且容易出錯的事務,例如記憶體管理。

 

Java虛擬機器將執行時記憶體區域劃分為五個部分,分別為方法區、堆、PC暫存器、Java方法棧和本地方法棧。Java程式編譯而成的class檔案,需要先載入至方法區中,方能在Java虛擬機器中執行。

為了提高執行效率,標準JDK中的HotSpot虛擬機器採用的是一種混合執行的策略。首先,它會解釋執行Java位元組碼,然後會將其中反覆執行的熱點程式碼,以方法為單位進行即時編譯,翻譯成機器碼後直接執行在底層硬體之上。HotSpot裝載了多個不同的即時編譯器,以便在編譯時間和生成程式碼的執行效率之間做取捨。

3、Java虛擬機器是如何載入Java類的?

 

Java虛擬機器將位元組流轉化為Java類的過程,可分為載入、連結以及初始化三大步驟。也可以用蓋房子來類比Java虛擬機器中的類載入。

 

載入是指查詢位元組流,並且據此建立類的過程。以蓋房子為例,村裡的Tony要蓋個房子,那麼按照流程他得先找個建築師,跟他說想要設計一個房型,比如說“一房、一廳、四衛”。這裡的房型相當於類,而建築師,就相當於類載入器。村裡有許多建築師,他們等級森嚴,但有著共同的祖師爺,叫啟動類載入器(boot class loader)。

 

載入需要藉助類載入器,在Java虛擬機器中,類載入器使用了雙親委派模型,即接收到載入請求時,會先將請求轉發給父類載入器。

 

連結,是指將建立成的類合併至Java虛擬機器中,使之能夠執行的過程。連結還分驗證、準備和解析三個階段。其中,解析階段為非必須的。

 

初始化,則是為標記為常量值的欄位賦值,以及執行<clinit>方法的過程。類的初始化僅會被執行一次,這個特性被用來實現單例的延遲初始化。這放在我們蓋房子的例子中就是,只有當房子裝修過後,Tony才能真正地住進去。

 

想了解更多JVM內容,可訂閱我的《深入拆解Java虛擬機器》專欄,已全部完結,一次性就可學習看完。

       

 

4、如何監控和診斷JVM堆內和堆外記憶體使用?

 

瞭解 JVM 記憶體的方法有很多,具體能力範圍也有區別,簡單總結如下:

可以使用綜合性的圖形化工具,如 JConsole、VisualVM(注意,從 Oracle JDK 9 開始,VisualVM 已經不再包含在 JDK 安裝包中)等。這些工具具體使用起來相對比較直觀,直接連線到 Java 程序,然後就可以在圖形化介面裡掌握記憶體使用情況。

以 JConsole 為例,其記憶體頁面可以顯示常見的堆記憶體和各種堆外部分使用狀態。

也可以使用命令列工具進行執行時查詢,如 jstat 和 jmap 等工具都提供了一些選項,可以檢視堆、方法區等使用資料。

或者,也可以使用 jmap 等提供的命令,生成堆轉儲(Heap Dump)檔案,然後利用 jhat 或 Eclipse MAT 等堆轉儲分析工具進行詳細分析。

如果你使用的是 Tomcat、Weblogic 等 Java EE 伺服器,這些伺服器同樣提供了記憶體管理相關的功能。

另外,從某種程度上來說,GC 日誌等輸出,同樣包含著豐富的資訊。

這裡有一個相對特殊的部分,就是是堆外記憶體中的直接記憶體,前面的工具基本不適用,可以使用 JDK 自帶的 Native Memory Tracking(NMT)特性,它會從 JVM 本地記憶體分配的角度進行解讀。

 

5、JVM的永久代中會發生垃圾回收麼?

垃圾回收不會發生在永久代,如果永久代滿了或者是超過了臨界值,會觸發完全垃圾回收(Full GC)。如果你仔細檢視垃圾收集器的輸出資訊,就會發現永久代也是被回收的。這就是為什麼正確的永久代大小對避免Full GC是非常重要的原因。

(注:Java8中已經移除了永久代,新加了一個叫做元資料區的native記憶體區) 異常處理

 

6、在Java中,物件什麼時候可以被垃圾回收?

當物件對當前使用這個物件的應用程式變得不可觸及的時候,這個物件就可以被回收了。

 

7、Java中的兩種異常型別是什麼?他們有什麼區別?

Java中有兩種異常:受檢查的(checked)異常和不受檢查的(unchecked)異常。不受檢查的異常不需要在方法或者是建構函式上宣告,就算方法或者是建構函式的執行可能會丟擲這樣的異常,並且不受檢查的異常可以傳播到方法或者是建構函式的外面。相反,受檢查的異常必須要用throws語句在方法或者是建構函式上宣告。這裡有Java異常處理的一些小建議。

 

8、JVM垃圾回收演算法

標記-清除演算法:首先標記出所有需要回收的物件,在標記完成後統一回收所有被標記的物件。

 

複製演算法:將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當一塊記憶體用完了,將還存另外一塊上面,然後在把已使用過的記憶體空間一次清理掉。

 

標記-整理演算法:標記過程與“標記-清除”演算法一樣,但後續步驟不是直接對可回收物件進行清理,而是讓所一端移動,然後直接清理掉端邊界以外的記憶體。

 

分代收集演算法:一般是把Java堆分為新生代和老年代,根據各個年代的特點採用最適當的收集演算法。新生代都發現有大批物件死去,選用複製演算法。老年代中因為物件存活率高,必須使用“標記-清理”或“標記-整理”演算法來進行回收。

 

專欄雖然到此已經結束了,但是並不代表你對Java虛擬機器學習的停止。我想,專欄的內容僅僅是為你打開了JVM學習的大門,裡面的風景,還是需要你自己來探索。在文章的後面,我列出了一系列的Java虛擬機器技術的相關部落格和閱讀資料,你仍然可以繼續加餐。

 

你可以關注國內幾位Java虛擬機器大咖的微信公眾號:

  1. R大,個人認為是中文圈子裡最瞭解Java虛擬機器設計實現的人,你可以關注他的[知乎賬號](https://www.zhihu.com/people/rednaxelafx);

  2. [你假笨](https://open.weixin.qq.com/qr/code?username=lovestblog),原阿里Java虛擬機器團隊成員,現[PerfMa](http://www.perfma.com/) CEO;

  3. [江南白衣](https://open.weixin.qq.com/qr/code?username=jnby1978),唯品會資深架構師;

  4. [佔小狼](https://open.weixin.qq.com/qr/code?username=whywhy_zj),美團基礎架構部技術專家;

  5. [楊曉峰](https://open.weixin.qq.com/qr/code?username=gh_9f3b2a4e2a74),前甲骨文首席工程師。

 

如果英文閱讀沒問題的話,你可以關注[Cliff Click](http://cliffc.org/blog/)、[Aleksey Shipilëv](https://shipilev.net/)(他的[JVM Anatomy Park](https://shipilev.net/jvm-anatomy-park/)十分有趣)和[Nitsan Wakart](http://psy-lob-saw.blogspot.com/)的部落格。

你也可以關注[Java Virtual Machine Language Submit](http://openjdk.java.net/projects/mlvm/jvmlangsummit/)和[Oracle Code One](https://www.oracle.com/code-one/index.html)(前身是JavaOne大會)中關於Java虛擬機器的演講,以便掌握Java的最新發展動向。

至於其他閱讀材料,你可以參考R大的這份[書單](https://www.douban.com/doulist/2545443/),或者這個[彙總貼](https://github.com/deephacks/awesome-jvm)。

 

 

道阻且長,努力加餐~!

 

可以說,Java虛擬機器就是每一位Java工程師進階加薪的利器,你想往上升,你想深入技術,不想一直停留在簡單開發,或者你在做Java效能分析、調優工作時,那麼,Java虛擬機器絕對是一把助力的利劍。

 

來源:https://mp.weixin.qq.com/s/3XEbQ8nKIytP0LRtyy6Lqg