JVM基本結構、類載入過程以及執行時記憶體溢位分析

5ingwings發表於2018-03-28

.java檔案 —javac—編譯器——>  .class檔案(位元組碼,可用於跨平臺,但易被反編譯) —JVM—直譯器——> 機器碼

JVM基本結構

JVM基本結構、類載入過程以及執行時記憶體溢位分析

類載入過程:

載入: 

主要是查詢class檔案 並建立class檔案的物件 載入策略為按需載入 即 使用到了該類 才載入

驗證:  

驗證 class檔案是否符合JVM的規定 

準備: 即對static的變數 進行記憶體分配和初始化 (private static int i=5;注意這裡的初始化不是賦值為5 而是初始化為0) 

解析: 有類或介面的解析,欄位解析,類方法解析,介面方法解析 

初始化: 執行靜態初始化器和靜態初始化成員變數 即上面初始化為5 


三種類載入器:

一、 啟動(BootStrap)類載入器 

載入的是JVM自身需要的類,使用的是C++編寫,將<JAVA_HOME>/lib下的核心類庫載入到記憶體中 

二、 擴充(Extension)類載入器 

載入<JAVA_HOME>/lib/ext目錄下或者由系統變數-Djava.ext.dir指定位路徑中的類庫 

三、 系統(System)類載入器 

載入系統類java -classpath或-D java.class.path 指定路徑下的類庫 


下面介紹類載入過程採用的機制——雙親委派模式

如果一個類載入器收到了類載入請求,它並不會自己先去載入,而是把這個請求委託給父類的載入器去執行,如果父類載入器還存在其父類載入器,則進一步向上委託,依次遞迴,請求最終將到達頂層的啟動類載入器,如果父類載入器可以完成類載入任務,就成功返回,倘若父類載入器無法完成此載入任務,子載入器才會嘗試自己去載入,這就是雙親委派模式

其實這裡叫做 “坑爹”模式更準確,因為當某一個類收到載入請求,並不是自己載入,而是交由父類載入,父類載入不了,才交回給之類載入

(注意 並非一定是繼承關係)

該模式的優點:

可以避免類的重複載入,防止核心類庫被篡改 如 通過網路傳遞一個名為java.lang.Integer的類,通過雙親委託模式傳遞到啟動類載入器,而啟動類載入器在核心Java API發現這個名字的類,發現該類已被載入,並不會重新載入網路傳遞的過來的java.lang.Integer類


程式碼層面分析:

abstract ClassLoader  

除了 啟動類載入器(BootStrap) 其他類載入器都繼承於該抽象類

主要方法有:

loadClass方法: 用於 實現 雙親委派模式 即 先在快取中找是否有該class物件,若有則不必重新載入了 若沒有 則去委託給父類載入器去載入 若 沒有父類 則委託給啟動載入器去載入 如果都沒有找到 則呼叫 findClass方法去查詢載入

findClass方法: 使用者把自定義的類載入邏輯寫於該方法中

defineClass方法: 通常與findClass()方法一起使用 將 位元組流解析成JVM能夠識別的class物件 

resolveClass方法:使類的class物件建立完成同時被解析 


執行緒上下文類載入器

  在Java應用中存在著很多服務提供者介面(Service Provider Interface,SPI),這些介面允許第三方為它們提供實現,如常見的 SPI 有 JDBC、JNDI等,這些 SPI 的介面屬於 Java 核心庫,一般存在rt.jar包中,由Bootstrap類載入器載入 但是 該BootStrap類載入器無法載入SPI的實現類 因此 要使用 執行緒上下文類載入器進行載入,但該方式破壞了 雙親委託模式 通過 getContextClassLoader和 setContextClassLoader 方法獲取和設定執行緒的上下文類載入器 初始化的上下文類載入器為AppClassLoader 



注意:

1 自定義的類載入器 是繼承於 APPClassLoader(即系統載入器)的 

2 在JVM中表示兩個class物件是否為同一個類物件存在兩個必要條件 類的完整類名必須一致,包括包名。 載入這個類的ClassLoader(指ClassLoader例項物件)必須相同。 


執行時記憶體溢位分析

執行時資料區域 :

執行緒共享區域: 1 方法區 2  java堆 3 執行時常量池 

 各個執行緒:  1 程式計數器 2 java虛擬機器棧 3 本地方法棧 4 棧幀 

記憶體溢位可能出現的區域

1 java堆 會出現 

Java.lang.OutOfMemoryError: ......Java heap space.....複製程式碼

這個溢位之前,可能系統會提前先報錯關鍵字為: 

java.lang.OutOfMemoryError:GC over head limit exceeded複製程式碼

 GC高頻回收 但是 效果不理想  

2 java虛擬機器棧、本地方法棧 會出現 

OutOfMemoryError   java.lang.StackOverflowError複製程式碼

3 方法區滿 會出現

OutOfMemoryError複製程式碼

java.lang.OutOfMemoryError: unable to create new native thread複製程式碼

 執行緒無法建立



參考文章:https://blog.csdn.net/javazejian/article/details/73413292


相關文章