Java常見面試題及答案 11-20(JVM),11-20jvm

來源:互聯網
上載者:User

Java常見面試題及答案 11-20(JVM),11-20jvm
11.JVM記憶體分哪幾個區,每個區的作用是什麼?

java虛擬機器主要分為以下一個區:

方法區:
1. 有時候也成為永久代,在該區內很少發生記憶體回收,但是並不代表不發生GC,在這裡進行的GC主要是對方法區裡的常量池和對類型的卸載
2. 方法區主要用來儲存已被虛擬機器載入的類的資訊、常量、靜態變數和即時編譯器編譯後的代碼等資料。
3. 該地區是被線程共用的。
4. 方法區裡有一個運行時常量池,用於存放靜態編譯產生的字面量和符號引用。該常量池具有動態性,也就是說常量並不一定是編譯時間確定,運行時產生的常量也會存在這個常量池中。

虛擬機器棧:
1. 虛擬機器棧也就是我們平常所稱的棧記憶體,它為java方法服務,每個方法在執行的時候都會建立一個棧幀,用於儲存局部變數表、運算元棧、動態連結和方法出口等資訊。
2. 虛擬機器棧是線程私人的,它的生命週期與線程相同。
3. 局部變數表裡儲存的是基礎資料型別 (Elementary Data Type)、returnAddress類型(指向一條位元組碼指令的地址)和對象引用,這個對象引用有可能是指向對象起始地址的一個指標,也有可能是代表對象的控制代碼或者與對象相關聯的位置。局部變數所需的記憶體空間在編譯器間確定
4.運算元棧的作用主要用來儲存運算結果以及運算的運算元,它不同於局部變數表通過索引來訪問,而是壓棧和出棧的方式
5.每個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用,持有這個引用是為了支援方法調用過程中的動態串連.動態連結就是將常量池中的符號引用在運行期轉化為直接引用。

本地方法棧
本地方法棧和虛擬機器棧類似,只不過本地方法棧為Native方法服務。


java堆是所有線程所共用的一塊記憶體,在虛擬機器啟動時建立,幾乎所有的對象執行個體都在這裡建立,因此該地區經常發生記憶體回收操作。

程式計數器
記憶體空間小,位元組碼解譯器工作時通過改變這個計數值可以選取下一條需要執行的位元組碼指令,分支、迴圈、跳轉、異常處理和線程恢複等功能都需要依賴這個計數器完成。該記憶體地區是唯一一個java虛擬機器規範沒有規定任何OOM情況的地區。

12.如和判斷一個對象是否存活?(或者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中的對象進行第二次被標記,這時,該對象將被移除”即將回收”集合,等待回收。

13.簡述java記憶體回收機制?

在java中,程式員是不需要顯示的去釋放一個對象的記憶體的,而是由虛擬機器自行執行。在JVM中,有一個記憶體回收線程,它是低優先順序的,在正常情況下是不會執行的,只有在虛擬機器空閑或者當前堆記憶體不足時,才會觸發執行,掃面那些沒有被任何引用的對象,並將它們添加到要回收的集合中,進行回收。

14.java中垃圾收集的方法有哪些?
  1. 標記-清除:
    這是垃圾收集演算法中最基礎的,根據名字就可以知道,它的思想就是標記哪些要被回收的對象,然後統一回收。這種方法很簡單,但是會有兩個主要問題:1.效率不高,標記和清除的效率都很低;2.會產生大量不連續的記憶體片段,導致以後程式在分配較大的對象時,由於沒有充足的連續記憶體而提前觸發一次GC動作。

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

  3. 標記-整理
    該演算法主要是為瞭解決標記-清除,產生大量記憶體片段的問題;當對象存活率較高時,也解決了複製演算法的效率問題。它的不同之處就是在清除對象的時候現將可回收對象移動到一端,然後清除掉端邊界以外的對象,這樣就不會產生記憶體片段了。

  4. 分代收集 
    現在的虛擬機器垃圾收集大多採用這種方式,它根據對象的生存周期,將堆分為新生代和老年代。在新生代中,由於物件存留期短,每次回收都會有大量對象死去,那麼這時就採用複製演算法。老年代裡的對象存活率較高,沒有額外的空間進行分配擔保,所以可以使用標記-整理 或者 標記-清除

15.java記憶體模型

java記憶體模型(JMM)是線程間通訊的控制機制.JMM定義了主記憶體和線程之間抽象關係。線程之間的共用變數儲存在主記憶體(main memory)中,每個線程都有一個私人的本地記憶體(local memory),本地記憶體中儲存了該線程以讀/寫共用變數的副本。本地記憶體是JMM的一個抽象概念,並不真實存在。它涵蓋了緩衝,寫緩衝區,寄存器以及其他的硬體和編譯器最佳化。Java記憶體模型的抽象如下:

從來看,線程A與線程B之間如要通訊的話,必須要經曆下面2個步驟:
1. 首先,線程A把本地記憶體A中更新過的共用變數重新整理到主記憶體中去。
2. 然後,線程B到主記憶體中去讀取線程A之前已更新過的共用變數。
寫的很好:http://www.infoq.com/cn/articles/java-memory-model-1

16.java類載入過程?

java類載入需要經曆一下7個過程:
載入
載入時類載入的第一個過程,在這個階段,將完成一下三件事情:
1. 通過一個類的全限定名擷取該類的二進位流。
2. 將該二進位流中的靜態儲存結構轉化為方法去運行時資料結構。 
3. 在記憶體中產生該類的Class對象,作為該類的資料訪問入口。

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

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

    public static int value=123;//在準備階段value初始值為0 。在初始化階段才會變為123 。
  • 1

  • 2

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

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

17. 簡述java類載入機制?

虛擬機器把描述類的資料從Class檔案載入到記憶體,並對資料進行校正,解析和初始化,最終形成可以被虛擬機器直接使用的java類型。

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

當一個類收到了類載入請求時,不會自己先去載入這個類,而是將其委派給父類,由父類去載入,如果此時父類不能載入,反饋給子類,由子類去完成類的載入。

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

實現通過類的許可權定名擷取該類的二進位位元組流的代碼塊叫做類載入器。
主要有一下四種類載入器:
1. 啟動類載入器(Bootstrap ClassLoader)用來載入java核心類庫,無法被java程式直接引用。
2. 擴充類載入器(extensions class loader):它用來載入 Java 的擴充庫。JAVA 虛擬機器的實現會提供一個擴充庫目錄。該類載入器在此目錄裡面尋找並載入 Java 類。
3. 系統類別載入器(system class loader):它根據 Java 應用的類路徑(CLASSPATH)來載入 Java 類。一般來說,Java 應用的類都是由它來完成載入的。可以通過 ClassLoader.getSystemClassLoader()來擷取它。
4. 使用者自訂類載入器,通過繼承 java.lang.ClassLoader類的方式實現。

20.簡述java記憶體配置與回收策率以及Minor GC和Major GC
  1. 對象優先在堆的Eden區分配。

  2. 大對象直接進入老年代.

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

長按二維碼關注我們  




相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.