Java虛擬機面試題總結

上次已經介紹了初識Java虛擬機淺談Java垃圾回收,今天來總結一下面試中常常遇到的有關Java虛擬機的面試題。程序員

  • 簡述Java垃圾回收機制
  • JVM內存分哪幾個區,每一個區的做用是什麼?
  • 如何判斷一個對象是否存活?
  • Java中垃圾收集的方法有哪些?
  • 談談類加載器雙親委派模型機制
  • 類加載器有哪些
  • 請解釋StackOverflowError和OutOfMemeryError的區別?
  • GC的回收流程是怎樣的

簡述Java垃圾回收機制

在Java中,程序員是不須要顯示的去釋放一個對象的內存的,而是由虛擬機自行執行。在JVM中,有一個垃圾回收線程,它是 低優先級的,在正常狀況下是不會執行的,只有在虛擬機空閒或者當前堆內存不足時,纔會觸發執行,掃面那些沒有被任何引用的對象,並將它們添加到要回收的集合中,進行回收。

JVM內存分哪幾個區,每一個區的做用是什麼?

Java虛擬機主要分爲如下幾個區:面試

方法區

1. 有時候也成爲永久代,在該區內不多發生垃圾回收,可是並不表明不發生GC,在這裏進行的GC主要是對方法區裏的常量池和對類型的卸載
2. 方法區主要用來存儲已被虛擬機加載的類的信息、常量、靜態變量和即時編譯器編譯後的代碼等數據。
3. 該區域是被線程共享的。
4. 方法區裏有一個運行時常量池,用於存放靜態編譯產生的字面量和符號引用。算法

虛擬機棧

1. 虛擬機棧也就是咱們日常所稱的棧內存,它爲Java方法服務,每一個方法在執行的時候都會建立一個棧幀,用於存儲局部變量表、操做數棧、動態連接和方法出口等信息。
2. 虛擬機棧是線程私有的,它的生命週期與線程相同。segmentfault

本地方法棧

本地方法棧和虛擬機棧相似,只不過本地方法棧爲Native方法服務。線程

Java堆是全部線程所共享的一塊內存,在虛擬機啓動時建立,幾乎全部的對象實例都在這裏建立,所以該區域常常發生垃圾回收操做。code

程序計數器

內存空間小,字節碼解釋器工做時經過改變這個計數值能夠選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理和線程恢復等功能都須要依賴這個計數器完成。對象

如何判斷一個對象是否存活?

判斷一個對象是否存活有兩種方法:遞歸

引用計數法

所謂引用計數法就是給每個對象設置一個引用計數器,每當有一個地方引用這個對象時,就將計數器加一,引用失效時,計數器就減一。當一個對象的引用計數器爲零時,說明此對象沒有被引用,也就是「死對象」,將會被垃圾回收.
引用計數法有一個缺陷就是沒法解決循環引用問題,也就是說當對象A引用對象B,對象B又引用者對象A,那麼此時A,B對象的引用計數器都不爲零,也就形成沒法完成垃圾回收,因此主流的虛擬機都沒有采用這種算法。生命週期

可達性算法

該算法的思想是:從一個被稱爲GC Roots的對象開始向下搜索,若是一個對象到GC Roots沒有任何引用鏈相連時,則說明此對象不可用。內存

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

  1. 標記-清除

    這是垃圾收集算法中最基礎的,根據名字就能夠知道,它的思想就是標記哪些要被回收的對象,而後統一回收。這種方法很簡單,可是會有兩個主要問題:1.效率不高,標記和清除的效率都很低;2.會產生大量不連續的內存碎片,致使之後程序在分配較大的對象時,因爲沒有充足的連續內存而提早觸發一次GC動做。

  2. 複製算法

    爲了解決效率問題,複製算法將可用內存按容量劃分爲相等的兩部分,而後每次只使用其中的一塊,當一塊內存用完時,就將還存活的對象複製到第二塊內存上,而後一次性清楚完第一塊內存,再將第二塊上的對象複製到第一塊。可是這種方式,內存的代價過高,每次基本上都要浪費一半的內存。
    因而將該算法進行了改進,內存區域再也不是按照1:1去劃分,而是將內存劃分爲8:1:1三部分,較大那分內存交Eden區,其他是兩塊較小的內存區叫Survior區。每次都會優先使用Eden區,若Eden區滿,就將對象複製到第二塊內存區上,而後清除Eden區,若是此時存活的對象太多,以致於Survivor不夠時,會將這些對象經過分配擔保機制複製到老年代中。(Java堆又分爲新生代和老年代)

  3. 標記-整理

    該算法主要是爲了解決標記-清除,產生大量內存碎片的問題;當對象存活率較高時,也解決了複製算法的效率問題。它的不一樣之處就是在清除對象的時候現將可回收對象移動到一端,而後清除掉端邊界之外的對象,這樣就不會產生內存碎片了。

  4. 分代收集 

    如今的虛擬機垃圾收集大多采用這種方式,它根據對象的生存週期,將堆分爲新生代和老年代。在新生代中,因爲對象生存期短,每次回收都會有大量對象死去,那麼這時就採用複製算法。老年代裏的對象存活率較高,沒有額外的空間進行分配擔保,因此可使用標記-整理 或者 標記-清除

談談類加載器雙親委派模型機制

當一個類收到了類加載請求時,不會本身先去加載這個類,而是將其委派給父類,由父類去加載,若是此時父類不能加載,反饋給子類,由子類去完成類的加載。

類加載器有哪些

  • Bootstrap ClassLoader
  • Extensions ClassLoader
  • App ClassLoader
  • 用戶自定義類加載器

請解釋StackOverflowError和OutOfMemeryError的區別?

StackOverflowError棧溢出,通常因爲遞歸過多,調用方法過多致使

OutOfMemeryError堆內存溢出,即OOM,因爲堆內存中沒有被GC回收的對象過多致使。

出現OOM的緣由:

  • Java虛擬機的堆內存設置不夠,能夠經過參數-Xms和-Xmx來調優
  • 程序中建立了大量對象,而且長時間不能被被垃圾回收器回收(存在引用)

GC的回收流程是怎樣的

GC回收流程以下:

對於整個的GC流程裏面,那麼最須要處理的就是新生代和老年代的內存清理操做,而元空間(永久代)都不在GC範圍內
當如今有一個新的對象產生,那麼對象必定須要內存空間。

一、首先會 判斷Eden區是否有內存空間,若是此時有內存空間,則直接將新對象保存在Eden區。

二、可是若是此時在Eden區內存不足,那麼會自動執行一個Minor GC 操做,將Eden區的無用內存空間進行清理,Minor GC的清理範圍只在Eden區,清理以後會繼續判斷Eden區的內存空間是否充足?若是內存空間充足,則將新對象直接在Eden區進行空間分配。

三、若是執行Minor GC 以後發現Eden區的內存空間依然不足,那麼這個時候會執行Survivor區的判斷,若是Survivor區有剩餘空間,則將Eden區部分活躍對象保存在Survivor區,那麼隨後繼續判斷Eden區的內存空間是否充足,若是充足怎則將新對象直接在Eden區進行空間分配。

四、此時若是Survivor區沒有內存空間,則繼續判斷老年區。若老年區有剩餘內存則將部分存活對象保存在老年代。

五、若是這個時候老年代也滿了,那麼這個時候將產生Major GC(Full GC),那麼這個時候將進行老年代的清理。

六、若是老年代執行Full GC以後,沒法進行對象的保存,則會產生OOM異常,OutOfMemoryError異常

相關文章
相關標籤/搜索