金三銀四面試季—20道精選JVM重點面試問題!

Java架構技術棧發表於2019-03-30

JVM 是小白 Java 程式設計師成長路上的一道坎也是很多工作2到3年程式設計師的一個重點面試問題之一,學習JVM之前,只需要知道程式碼編譯成 Class,虛擬機器載入 Class 執行就可以了,學習 JVM 之後,可以深入理解程式碼從編譯到載入的過程、記憶體中物件的建立與垃圾回收、日常開發中快速定位效能問題等,當然也是面試不可缺少的加分項。在這我整理20道精選的JVM面試題分享給大家,希望能幫助到大家同時可以點個贊關注下,多謝支援!

面試問題如下:

1.Java 類載入過程?

答:Java 類載入需要經歷一下 7 個過程:

1. 載入

載入是類載入的第一個過程,在這個階段,將完成一下三件事情:

  • 通過一個類的全限定名獲取該類的二進位制流。
  • 將該二進位制流中的靜態儲存結構轉化為方法去執行時資料結構。
  • 在記憶體中生成該類的 Class 物件,作為該類的資料訪問入口。

2. 驗證

驗證的目的是為了確保 Class 檔案的位元組流中的資訊不回危害到虛擬機器.在該階段主要完成以下四鍾驗證:

  • 檔案格式驗證:驗證位元組流是否符合 Class 檔案的規範,如主次版本號是否在當前虛擬機器範圍內,常量池中的常量是否有不被支援的型別.
  • 後設資料驗證:對位元組碼描述的資訊進行語義分析,如這個類是否有父類,是否整合了不被繼承的類等。
  • 位元組碼驗證:是整個驗證過程中最複雜的一個階段,通過驗證資料流和控制流的分析,確定程式語義是否正確,主要針對方法體的驗證。如:方法中的型別轉換是否正確,跳轉指令是否正確等。
  • 符號引用驗證:這個動作在後面的解析過程中發生,主要是為了確保解析動作能正確執行。

3. 準備

準備階段是為類的靜態變數分配記憶體並將其初始化為預設值,這些記憶體都將在方法區中進行分配。準備階段不分配類中的例項變數的記憶體,例項變數將會在物件例項化時隨著物件一起分配在 Java 堆中。

public static int value=123;//在準備階段value初始值為0 。在初始化階段才會變為123 複製程式碼

4. 解析

該階段主要完成符號引用到直接引用的轉換動作。解析動作並不一定在初始化動作完成之前,也有可能在初始化之後。

5. 初始化

初始化時類載入的最後一步,前面的類載入過程,除了在載入階段使用者應用程式可以通過自定義類載入器參與之外,其餘動作完全由虛擬機器主導和控制。到了初始化階段,才真正開始執行類中定義的 Java 程式程式碼。

6. 使用

7. 解除安裝

2.描述一下 JVM 載入 Class 檔案的原理機制?

答:Java 語言是一種具有動態性的解釋型語言,類(Class)只有被載入到 JVM 後才能執行。當執行指定程式時,JVM 會將編譯生成的 .class 檔案按照需求和一定的規則載入到記憶體中,並組織成為一個完整的 Java 應用程式。這個載入過程是由類載入器完成,具體來說,就是由 ClassLoader 和它的子類來實現的。類載入器本身也是一個類,其實質是把類檔案從硬碟讀取到記憶體中。

類的載入方式分為隱式載入和顯示載入。隱式載入指的是程式在使用 new 等方式建立物件時,會隱式地呼叫類的載入器把對應的類載入到 JVM 中。顯示載入指的是通過直接呼叫 class.forName() 方法來把所需的類載入到 JVM 中。

任何一個工程專案都是由許多類組成的,當程式啟動時,只把需要的類載入到 JVM 中,其他類只有被使用到的時候才會被載入,採用這種方法一方面可以加快載入速度,另一方面可以節約程式執行時對記憶體的開銷。此外,在 Java 語言中,每個類或介面都對應一個 .class 檔案,這些檔案可以被看成是一個個可以被動態載入的單元,因此當只有部分類被修改時,只需要重新編譯變化的類即可,而不需要重新編譯所有檔案,因此加快了編譯速度。

在 Java 語言中,類的載入是動態的,它並不會一次性將所有類全部載入後再執行,而是保證程式執行的基礎類(例如基類)完全載入到 JVM 中,至於其他類,則在需要的時候才載入。

類載入的主要步驟:

  • 裝載,根據查詢路徑找到相應的 class 檔案,然後匯入。
  • 連結,連結又可分為 3 個小步:
  • 檢查,檢查待載入的 class 檔案的正確性。
  • 準備,給類中的靜態變數分配儲存空間。
  • 解析,將符號引用轉換為直接引用(這一步可選)
  • 初始化。對靜態變數和靜態程式碼塊執行初始化工作。

3. Java 記憶體分配。

  • 暫存器:我們無法控制。
  • 靜態域:static定義的靜態成員。
  • 常量池:編譯時被確定並儲存在 .class 檔案中的(final)常量值和一些文字修飾的符號引用(類和介面的全限定名,欄位的名稱和描述符,方法和名稱和描述符)。
  • 非 RAM 儲存:硬碟等永久儲存空間。
  • 堆記憶體:new 建立的物件和陣列,由 Java 虛擬機器自動垃圾回收器管理,存取速度慢。
  • 棧記憶體:基本型別的變數和物件的引用變數(堆記憶體空間的訪問地址),速度快,可以共享,但是大小與生存期必須確定,缺乏靈活性。

4.Java 堆的結構是什麼樣子的?什麼是堆中的永久代(Perm Gen space)?

答:JVM 的堆是執行時資料區,所有類的例項和陣列都是在堆上分配記憶體。它在 JVM 啟動的時候被建立。物件所佔的堆記憶體是由自動記憶體管理系統也就是垃圾收集器回收。

堆記憶體是由存活和死亡的物件組成的。存活的物件是應用可以訪問的,不會被垃圾回收。死亡的物件是應用不可訪問尚且還沒有被垃圾收集器回收掉的物件。一直到垃圾收集器把這些 物件回收掉之前,他們會一直佔據堆記憶體空間。

5.GC 是什麼? 為什麼要有 GC?

答:GC 是垃圾收集的意思(GabageCollection),記憶體處理是程式設計人員容易出現問題的地方,忘記或者錯誤的記憶體回收會導致程式或系統的不穩定甚至崩潰,Java 提供的 GC 功能可以自動監測物件是否超過作用域從而達到自動回收記憶體的目的,Java 語言沒有提供釋放已分配記憶體的顯示操作方法。

6.簡述 Java 垃圾回收機制?

答:在 Java 中,程式設計師是不需要顯示的去釋放一個物件的記憶體的,而是由虛擬機器自行執行。在 JVM 中,有一個垃圾回收執行緒,它是低優先順序的,在正常情況下是不會執行的,只有在虛擬機器空閒或者當前堆記憶體不足時,才會觸發執行,掃面那些沒有被任何引用的物件,並將它們新增到要回收的集合中,進行回收。

7. 如何判斷一個物件是否存活?(或者 GC 物件的判定方法)

答:判斷一個物件是否存活有兩種方法:

1. 引用計數法

所謂引用計數法就是給每一個物件設定一個引用計數器,每當有一個地方引用這個物件時,就將計數器加一,引用失效時,計數器就減一。當一個物件的引用計數器為零時,說明此物件沒有被引用,也就是“死物件”,將會被垃圾回收.

引用計數法有一個缺陷就是無法解決迴圈引用問題,也就是說當物件 A 引用物件 B,物件 B 又引用者物件 A,那麼此時 A、B 物件的引用計數器都不為零,也就造成無法完成垃圾回收,所以主流的虛擬機器都沒有采用這種演算法。

2. 可達性演算法(引用鏈法)

該演算法的思想是:從一個被稱為 GC Roots 的物件開始向下搜尋,如果一個物件到 GC Roots 沒有任何引用鏈相連時,則說明此物件不可用。

在 Java 中可以作為 GC Roots 的物件有以下幾種:

  • 虛擬機器棧中引用的物件
  • 方法區類靜態屬性引用的物件
  • 方法區常量池引用的物件
  • 本地方法棧JNI引用的物件

雖然這些演算法可以判定一個物件是否能被回收,但是當滿足上述條件時,一個物件比不一定會被回收。當一個物件不可達 GC Root 時,這個物件並不會立馬被回收,而是出於一個死緩的階段,若要被真正的回收需要經歷兩次標記.

如果物件在可達性分析中沒有與 GC Root 的引用鏈,那麼此時就會被第一次標記並且進行一次篩選,篩選的條件是是否有必要執行 finalize() 方法。當物件沒有覆蓋 finalize() 方法或者已被虛擬機器呼叫過,那麼就認為是沒必要的。 如果該物件有必要執行 finalize() 方法,那麼這個物件將會放在一個稱為 F-Queue 的對佇列中,虛擬機器會觸發一個 Finalize() 執行緒去執行,此執行緒是低優先順序的,並且虛擬機器不會承諾一直等待它執行完,這是因為如果 finalize() 執行緩慢或者發生了死鎖,那麼就會造成 F-Queue 佇列一直等待,造成了記憶體回收系統的崩潰。GC 對處於 F-Queue 中的物件進行第二次被標記,這時,該物件將被移除” 即將回收” 集合,等待回收。

8.垃圾回收的優點和原理。並考慮 2 種回收機制?

答:Java 語言中一個顯著的特點就是引入了垃圾回收機制,使 C++ 程式設計師最頭疼的記憶體管理的問題迎刃而解,它使得 Java 程式設計師在編寫程式的時候不再需要考慮記憶體管理。由於有個垃圾回收機制,Java 中的物件不再有“作用域”的概念,只有物件的引用才有"作用域"。垃圾回收可以有效的防止記憶體洩露,有效的使用可以使用的記憶體。垃圾回收器通常是作為一個單獨的低階別的執行緒執行,不可預知的情況下對記憶體堆中已經死亡的或者長時間沒有使用的物件進行清楚和回收,程式設計師不能實時的呼叫垃圾回收器對某個物件或所有物件進行垃圾回收。

回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。

9.什麼是分散式垃圾回收(DGC)?它是如何工作的?

答:DGC 叫做分散式垃圾回收。RMI 使用 DGC 來做自動垃圾回收。因為 RMI 包含了跨虛擬機器的遠端物件的引用,垃圾回收是很困難的。DGC 使用引用計數演算法來給遠端物件提供自動記憶體管理。

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

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

11.簡述 Java 記憶體分配與回收策率以及 Minor GC 和 Major GC。

  • 物件優先在堆的 Eden 區分配
  • 大物件直接進入老年代
  • 長期存活的物件將直接進入老年代

當 Eden 區沒有足夠的空間進行分配時,虛擬機器會執行一次 Minor GC。Minor GC 通常發生在新生代的 Eden 區,在這個區的物件生存期短,往往發生 Gc 的頻率較高,回收速度比較快;Full GC/Major GC 發生在老年代,一般情況下,觸發老年代 GC 的時候不會觸發 Minor GC,但是通過配置,可以在 Full GC 之前進行一次 Minor GC 這樣可以加快老年代的回收速度。

12.序列(serial)收集器和吞吐量(throughput)收集器的區別是什麼?

答:吞吐量收集器使用並行版本的新生代垃圾收集器,它用於中等規模和大規模資料的應用程式。 而序列收集器對大多數的小應用(在現代處理器上需要大概 100M 左右的記憶體)就足夠了。

13.Java 中垃圾收集的方法有哪些?

可以參考之前的一篇文章:JVM的判斷物件是否已死和四種垃圾回收演算法

14.什麼是類載入器,類載入器有哪些?

答:實現通過類的許可權定名獲取該類的二進位制位元組流的程式碼塊叫做類載入器。

主要有一下四種類載入器:

  • 啟動類載入器(Bootstrap ClassLoader)用來載入 Java 核心類庫,無法被 Java 程式直接引用。
  • 擴充套件類載入器(extensions class loader):它用來載入 Java 的擴充套件庫。Java 虛擬機器的實現會提供一個擴充套件庫目錄。該類載入器在此目錄裡面查詢並載入 Java 類。
  • 系統類載入器(system class loader):它根據 Java 應用的類路徑(CLASSPATH)來載入 Java 類。一般來說,Java 應用的類都是由它來完成載入的。可以通過 ClassLoader.getSystemClassLoader() 來獲取它。
  • 使用者自定義類載入器,通過繼承 java.lang.ClassLoader 類的方式實現。

15.類載入器雙親委派模型機制?

可以參考之前我發過的一篇文章JVM面試問題系列:Java類載入機制之雙親委派模型

16.垃圾回收器的基本原理是什麼?垃圾回收器可以馬上回收記憶體嗎?有什麼辦法主動通知虛擬機器進行垃圾回收?

答:對於 GC 來說,當程式設計師建立物件時,GC 就開始監控這個物件的地址、大小以及使用情況。通常,GC 採用有向圖的方式記錄和管理堆(heap)中的所有物件。通過這種方式確定哪些物件是”可達的”,哪些物件是”不可達的”。當 GC 確定一些物件為“不可達”時,GC 就有責任回收這些記憶體空間。可以。程式設計師可以手動執行 System.gc(),通知 GC 執行,但是 Java 語言規範並不保證 GC 一定會執行。

17.System.gc() 和 Runtime.gc() 會做什麼事情?

答:這兩個方法用來提示 JVM 要進行垃圾回收。但是,立即開始還是延遲進行垃圾回收是取決於 JVM 的。

18.finalize() 方法什麼時候被呼叫?解構函式 (finalization) 的目的是什麼?

答:垃圾回收器(garbage colector)決定回收某物件時,就會執行該物件的 finalize() 方法 但是在 Java 中很不幸,如果記憶體總是充足的,那麼垃圾回收可能永遠不會進行,也就是說 filalize() 可能永遠不被執行,顯然指望它做收尾工作是靠不住的。 那麼 finalize() 究竟是做什麼的呢? 它最主要的用途是回收特殊渠道申請的記憶體。Java 程式有垃圾回收器,所以一般情況下記憶體問題不用程式設計師操心。但有一種 JNI(Java Native Interface)呼叫 non-­Java 程式(C 或 C++), finalize() 的工作就是回收這部分的記憶體。

19.Java 中會存在記憶體洩漏嗎,請簡單描述。

此題我後面會單獨寫篇文章,有興趣的朋友可以關注下和點個喜歡,謝謝支援!

20.如何判斷物件是否已死

可以參考之前的一篇文章:JVM的判斷物件是否已死和四種垃圾回收演算法

JVM與效能優化學習導圖筆記:

(此Xmind圖是平時學習時做的一些筆記和重點縮略未展開)

金三銀四面試季—20道精選JVM重點面試問題!

最後

後續會持續更新,大家覺得不錯可以點個贊在關注下我,以後還會分享更多文章!

同時在這給大家推薦一個微信公眾號,那裡每天都會有技術乾貨、技術動向、職業生涯、行業熱點、職場趣事等一切有關於程式設計師的內容分享。更有海量Java架構、移動網際網路架構相關原始碼視訊,面試資料,電子書籍截止於4月28日免費發放。我看了覺得資源還不錯,如果你們有需要的話,掃描下方二維碼關注wx公眾號免費獲取↓↓↓

金三銀四面試季—20道精選JVM重點面試問題!

資源大本營↓↓↓

Java架構資料
Java原始碼解析,到各種框架學習,再到專案實戰,一應俱全,包括但不限於:Spring、Mybatis等原始碼、Java進階、Java架構師、虛擬機器、效能優化、併發程式設計、資料結構和演算法。

金三銀四面試季—20道精選JVM重點面試問題!

金三銀四面試季—20道精選JVM重點面試問題!

金三銀四面試季—20道精選JVM重點面試問題!


相關文章