.java檔案 —javac—編譯器——> .class檔案(位元組碼,可用於跨平臺,但易被反編譯) —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