常見JVM問題
- JVM記憶體模型,GC機制和原理。 注意JVM記憶體模型與Java記憶體模型(JMM)不是同一個東西。 JVM = 類載入器(classloader) + 執行引擎(execution engine) + 執行時資料區域(runtime data area)
- PC暫存器:儲存JVM正在執行的位元組碼指令地址。如果是native的,那麼pc暫存器的值為undefined
- JVM Stack:儲存區域性變數與一些過程結果的地方。在方法呼叫和返回中也扮演了很重要的角色。
- Heap:堆是可以可供各個執行緒共享的執行時儲存區域,也是供所有類的例項和陣列物件分配記憶體的區域。堆在JVM啟動的時候建立。堆所儲存的就是被GC所管理的各種物件。
- Method Area:各個執行緒共享的執行時記憶體區,它儲存每一個類的例項資訊,執行時常量池,欄位和方法資料,建構函式和普通方法的位元組碼等內容。還有一些特殊方法。
- Run-Time Constant Pool:在方法區中分配,在載入類和介面到虛擬機器之後,就建立對應的執行時常量池。
- Native Method Stacks:JDK中native的方法,System類和Thread類中有很多。使用C語言編寫的方法,這個也通常叫做C stack。
- GC分哪兩種,Minor GC 和Full GC有什麼區別?什麼時候會觸發Full GC?分別採用什麼演算法?
- 從年輕代空間(包括 Eden 和 Survivor 區域)回收記憶體被稱為 Minor GC。當Eden區滿時,觸發Minor GC。
- Full GC 是清理整個堆空間—包括年輕代和老年代。Major GC通常是跟full GC是等價的,收集整個GC堆。
- 呼叫System.gc時,系統建議執行Full GC,但是不必然執行,
- 由Eden區、From Space區向To Space區複製時,物件大小大於To Space可用記憶體,則把該物件轉存到老年代,且老年代的可用記憶體小於該物件大小
- 老年代空間不足
- 通過Minor GC後進入老年代的平均大小大於老年代的可用記憶體
Minor GC採用複製演算法,將Eden區的物件複製到Suvivor空間,然後進行清除 Full Gc採用的是標記-壓縮演算法,讓所有的物件都向一端移動,然後直接清理掉端邊界以外的記憶體。
- JVM裡的有幾種classloader,為什麼會有多種? JDK中預設情況下有三種,如下圖
- BootStrap ClassLoader,負責載入<JAVA_HOME>/lib或被-Xbootclasspath指定路徑下的類庫,開發者不可以直接使用
- Extension ClassLoader,負責載入<JAVA_HOME>/lib/ext或被java.ext.dirs系統變數指定的路徑中的所有類庫,開發者可以直接使用
- App ClassLoader,這個類載入器是ClassLoader.getSystemClassLoader()的返回值,負責載入使用者類路徑上所指定的類庫,開發者可以直接使用這個類載入器,如果應用程式沒有自定義過類載入器,那麼系統預設使用這個類載入器。
如果一個類收到了類載入的請求,它首先不會自己去嘗試載入這個類,而是把請求委派給父類來實現,每一個層次的類載入器都是這樣,因此所有的類載入請求都會最終傳送到啟動類載入器,只有當父類載入器無法完成這個載入請求,子類載入器才會自己嘗試載入。
好處:避免記憶體中出現同樣的位元組碼。可以很好的解決各個類載入器的基礎類統一問題。
參考:JVM是如何載入類的?
- 什麼情況下我們需要破壞雙親委派模型? 熱替換,熱部署。OSGI是Java業界廣泛認可的模組化標準,而OSGI模組化熱部署的關鍵是它自定義的類載入器。每一個模組都有一個自己的類載入器,當需要更換一個 Bundle(包) 時,Bundle連同類載入器一同替換實現程式碼熱部署。
弄懂了OSGi的精髓,就可以算是掌握了類載入器的精髓
參考:JVM是如何載入類的?
-
常見的JVM調優方法有哪些?可以具體到調整哪個引數,調成什麼值? 主要調節吞吐量和響應時間: 參考: 記一次JVM調優 如何解決OutOfMemoryError
-
JVM class檔案結構是如何解析的;
-
可見性,重排序,final關鍵字 可見性是指一個執行緒修改某個共享變數的值的時候,其它執行緒能立刻得知。 重排序是底層做的優化,有些程式碼會在機器層面上提前執行,從而出現不正常的結果 final在Java中是一個保留的關鍵字,可以宣告成員變數、方法、類以及本地變數。一旦你將引用宣告作final,你將不能改變這個引用了,編譯器會檢查程式碼,如果你試圖將變數再次初始化的話,編譯器會報編譯錯誤。
參考:深入理解final關鍵字 8. Java物件模型 每一個Java類,在被JVM載入的時候,JVM會給這個類建立一個instanceKlass,儲存在方法區,用來在JVM層表示該Java類。當我們在Java程式碼中,使用new建立一個物件的時候,JVM會建立一個instanceOopDesc物件,這個物件中包含了兩部分資訊,物件頭以及後設資料。物件頭中有一些執行時資料,其中就包括和多執行緒相關的鎖的資訊。後設資料其實維護的是指標,指向的是物件所屬的類的instanceKlass。
這個內容比較多,需要深入理解
參考:Java物件模型
-
oop-klass
-
物件存活判定 可達性分析演算法:可達性分析,通過一系列"GC Roots"的物件作為起始點,往下走,一個物件到GC roots沒有任何引用的時候,則證明物件是不可用的 可作為GC roots的物件:
- 虛擬機器棧中引用的物件
- 方法區中類靜態屬性引用的物件
- 方法區中常量引用的物件
- 本地方法棧中JNI引用的物件
- Java的引用型別
- 強引用:正常物件賦值的語句,String a = "abc";強引用可以直接訪問目標物件,並且不會被系統回收,強引用可能導致記憶體洩漏
- 軟引用:比強引用稍微弱一點的型別,只有再記憶體不足的情況下才會被回收。如果再記憶體足夠的時候,呼叫System.gc()也不會回收軟引用的物件。
- 弱引用:比軟引用弱一點的引用型別,只要發現弱引用,都會將物件進行回收。
- 虛引用:最弱的一個引用型別,一個持有虛引用的物件,和沒有引用幾乎是一樣的。虛引用必須和引用佇列一起使用,它的作用在於跟蹤垃圾回收的過程。
參考:Java Primitive type與References type
最後
本文持續更新...