JVM面試十問
1. JVM執行時劃分哪幾個區域?哪些區域是執行緒共享的?哪些區域是執行緒獨佔的?
JVM執行時一共劃分:程式計數器、虛擬機器棧、堆、本地方法棧、方法區。
執行緒共享的資料區域:堆、方法區。
執行緒獨享的資料區域區域:程式計數器、虛擬機器棧、本地方法棧。
2. 這幾個記憶體區域分別存放什麼資料?
程式計數器記錄當前執行緒執行的位置;
虛擬機器棧儲存基本資料型別以及物件的引用等;
堆儲存物件例項;
本地方法棧與虛擬機器棧類似,它為Native方法服務;
方法區儲存被JVM載入的類資訊、常量、靜態變數等。
3. GC回收演算法
(1)標記-清除演算法:首先標記出需要回收的物件,標記完成後統一清除。此演算法缺點是標記-清楚效率不高,且容易出現大量不連續的碎片空間。
(2)複製演算法:將記憶體空間劃分成兩部分,每次只使用一個記憶體空間部分,當一個記憶體空間使用完,將會把存活的物件複製到另一空間,然後一次性清理掉該部分空間。此演算法缺點是記憶體利用率較低,只有一半。
(3)標記-整理演算法:和標記-清楚演算法相同也是先標記出需要回收的物件,但在標記完成後不是直接清除而是將存活的物件像一側進行移動,再清除邊界之外的記憶體。
4. 這三種GC回收演算法在JVM中是如何應用的?
GC主要發生在JVM的堆記憶體中,堆記憶體分為"新生代"和"老年代",新生代的GC稱為"Minor GC",老年代的GC稱為"Major GC"。
新生代中的GC演算法使用複製演算法:新生代中分為了Eden區和Survivor區(Survivor from和Survivor to),新產生的物件例項先在Eden區,Eden區滿了過後再在Survivor from區,如果Survivor from區也滿了後,將進行Minor GC(複製演算法),將存活的物件複製到Survivor to區,此時清除Eden區和Survivor from區,此時Survivor from成為新的Survivor to。新的物件又將在Eden區域進行分配,周而復始。
老年代中的GC演算法使用標記-清除演算法/標記-整理演算法,視具體的GC回收器而定。
5. 頻繁的Full GC會帶來什麼問題?
CPU佔用率過高,系統出現卡頓。
6. 什麼是OOM記憶體溢位,它發生在哪塊記憶體區域
OOM通常發生在堆記憶體上,指的是記憶體物件沒有及時回收,造成沒有多餘的記憶體分配給新的物件,此時應該定位程式中是否在頻繁建立物件而沒有及時回收,或者設定JVM的引數-Xms、-Xmx。
但OOM還有一種情況發生在虛擬機器棧,此時虛擬機器棧並不是因為遞迴太深造成StackOverflow,而是的的確確發生了OOM。首先,虛擬機器棧作為執行緒獨享的記憶體區域,總的虛擬機器棧記憶體大小有限,也就是可分配的執行緒大小有限,當每個虛擬機器棧設定的記憶體大小過大時,此時可分配的執行緒大小就變少,繼續建立過多的執行緒可能會導致無法再分配記憶體空間,造成虛擬機器棧的OOM。此時的解決辦法時,適當設定虛擬機器棧的記憶體大小-Xss,以便能建立更多的執行緒。
7.常用的GC回收器有哪些,有什麼特點?
CMS:通常對老年代的物件進行GC,基於標記-清除演算法,是一個低停頓、併發收集的GC回收器。它的GC過程一共分為4個步驟:
①初始標記,標記GC Roots能關聯的物件(即存活的物件),會停止使用者執行緒。
②併發標記,不會停止使用者執行緒,和使用者執行緒一起工作標記可達物件。
③重新標記,標記因為在“併發標記”階段新產生的物件。
④併發清除,同用戶執行緒一起工作,清理需要清理的物件。
缺點:
①佔用CPU資源
②無法處理併發標記期間產生的浮動垃圾
③由於採用標記-清楚演算法,會產生大量的記憶體碎片
G1:應用於整個堆上的記憶體,物理上不再劃分年輕代與老年代,只做邏輯保留,採用標記-整理演算法,是一個可對停頓時間預測的低停頓、併發收集的GC回收器。它的GC過程同CMS類似,一共分為4個步驟:
①初始標記,同CMS回收器一致,標記出存活的物件。
②併發標記,同CMS回收器一致,和使用者執行緒併發標記出存活的物件。
③最終標記,同CMS回收器一致,修正在併發標記將期間使用者執行緒新產生的物件。
④篩選回收,這個階段可根據使用者期望的GC停頓時間制定回收計劃。
8. 類在JVM中的載入過程
Java檔案被編譯為Class位元組碼檔案後被載入到JVM中,主要分為三步:載入 -> 連線 -> 初始化。連線過程又分為:驗證 -> 準備 -> 解析。
9. 類是如何被載入到JVM中的
Java檔案被編譯成Class位元組碼檔案後,通過類載入器被載入到JVM中。類載入器從上往下一共有:啟動類載入器、擴充套件類載入器、應用程式類載入器、自定義類載入器。類先從自定義類載入器開始,逐層向上傳遞到啟動類載入器,當啟動類載入器不能載入時,再向擴充套件類載入器載入,這稱為雙親委派模型。
10. 類載入器的雙親委派模型有什麼好處
假設一個類首先被自定義類載入器載入,我們寫Object類時,系統中就會出現不同的Object類。為了保證在系統中始終都只有一個Object類,方法就是它們都通過啟動類載入器載入。
這是一個能給程式設計師加buff的公眾號 (CoderBuff)