前言
本來想著給自己放鬆一下,刷刷部落格,突然被幾道面試題難倒!說說Java記憶體結構?說說物件分配規則?描述一下JVM載入class檔案的原理機制?似乎有點模糊了,那就大概看一下面試題吧。好記性不如爛鍵盤
*** 12萬字的java面試題整理 ***
Java記憶體結構
方法區和堆是所有執行緒共享的記憶體區域;而java棧、本地方法棧和程式設計師計數器是執行是執行緒私有的記憶體區域。
- Java堆(Heap),是Java虛擬機器所管理的記憶體中最大的一塊。Java堆是被所有執行緒共享的一塊內
存區域,在虛擬機器啟動時建立。此記憶體區域的唯一目的就是存放物件例項,幾乎所有的物件例項都在這裡分配記憶體。 - 方法區(Method Area),方法區(Method Area)與Java堆一樣,是各個執行緒共享的記憶體區域,它用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。
- 程式計數器(Program Counter Register),程式計數器(Program Counter Register)是一塊較小的記憶體空間,它的作用可以看做是當前執行緒所執行的位元組碼的行號指示器。
- JVM棧(JVM Stacks),與程式計數器一樣,Java虛擬機器棧(Java Virtual Machine Stacks)也是執行緒私有的,它的生命週期與執行緒相同。虛擬機器棧描述的是Java方法執行的記憶體模型:每個方法被執行的時候都會同時建立一個棧幀(Stack Frame)用於儲存區域性變數表、操作棧、動態連結、方法出口等資訊。每一個方法被呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器棧中從入棧到出棧的過程。
- 本地方法棧(Native Method Stacks),本地方法棧(Native Method Stacks)與虛擬機器棧所發揮的作用是非常相似的,其區別不過是虛擬機器棧為虛擬機器執行Java方法(也就是位元組碼)服務,而本地方法棧則是為虛擬機器使用到的Native方法服務。
說說物件分配規則
- 物件優先分配在Eden區,如果Eden區沒有足夠的空間時,虛擬機器執行一次Minor GC。
- 大物件直接進入老年代(大物件是指需要大量連續記憶體空間的物件)。這樣做的目的是避免在Eden區和兩個Survivor區之間發生大量的記憶體複製(新生代採用複製演算法收集記憶體)。
- 長期存活的物件進入老年代。虛擬機器為每個物件定義了一個年齡計數器,如果物件經過了1次Minor GC那麼物件會進入Survivor區,之後每經過一次Minor GC那麼物件的年齡加1,知道達到閥值物件進入老年區。
- 動態判斷物件的年齡。如果Survivor區中相同年齡的所有物件大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的物件可以直接進入老年代。
- 空間分配擔保。每次進行Minor GC時,JVM會計算Survivor區移至老年區的物件的平均大小,如果這個值大於老年區的剩餘值大小則進行一次Full GC,如果小於檢查HandlePromotionFailure設定,如果true則只進行Monitor GC,如果false則進行Full GC。
描述一下JVM載入class檔案的原理機制?
JVM中類的裝載是由類載入器(ClassLoader)和它的子類來實現的,Java中的類載入器是一個重要的Java執行時系統元件,它負責在執行時查詢和裝入類檔案中的類。
由於Java的跨平臺性,經過編譯的Java源程式並不是一個可執行程式,而是一個或多個類檔案。當Java程式需要使用某個類時,JVM會確保這個類已經被載入、連線(驗證、準備和解析)和初始化。
類的載入是指把類的.class檔案中的資料讀入到記憶體中,通常是建立一個位元組陣列讀入.class檔案,然後產生與所載入類對應的Class物件。
載入完成後,Class物件還不完整,所以此時的類還不可用。當類被載入後就進入連線階段,這一階段包括驗證、準備(為靜態變數分配記憶體並設定預設的初始值)和解析(將符號引用替換為直接引用)三個步驟。
最後JVM對類進行初始化,包括:
1)如果類存在直接的父類並且這個類還沒有被初始化,那麼就先初始化父類;
2)如果類中存在初始化語句,就依次執行這些初始化語句。 類的載入是由類載入器完成的,類載入器包括:根載入器(BootStrap)、擴充套件載入器(Extension)、系統載入器(System)和使用者自定義類載入器(java.lang.ClassLoader的子類)。
從Java 2(JDK 1.2)開始,類載入過程採取了父親委託機制(PDM)。PDM更好的保證了Java平臺的安全性,在該機制中,JVM自帶的Bootstrap是根載入器,其他的載入器都有且僅有一個父類載入器。
類的載入首先請求父類載入器載入,父類載入器無能為力時才由其子類載入器自行載入。JVM不會向Java程式提供對Bootstrap的引用。下面是關於幾個類載入器的說明
- Bootstrap:一般用原生代碼實現,負責載入JVM基礎核心類庫(rt.jar);
- Extension:從java.ext.dirs系統屬性所指定的目錄中載入類庫,它的父載入器是Bootstrap;
- System:又叫應用類載入器,其父類是Extension。它是應用最廣泛的類載入器。它從環境變數classpath或者系統屬性java.class.path所指定的目錄中記載類,是使用者自定義載入器的預設父載入器。