JVM類載入過程與雙親委派模型
- 2019 年 10 月 16 日
- 筆記
類載入過程
類載入過程為JVM將類描述數據從.class文件中載入到記憶體,並對數據進行解析和初始化,最終形成被JVM直接使用的Java類型。包含:
- 載入:獲取該類的二進位位元組流,將位元組流代表的靜態存儲結構轉化為方法區的運行時數據結構,並在記憶體生成代表該類的 java.lang.Object 對象作為方法區該類的訪問入口
- 驗證:確保 Class 文件的位元組流中包含的資訊符號當前虛擬機的要求(文件格式驗證、元數據驗證、位元組碼驗證、符號引用驗證)
- 準備:為類變數分配記憶體並設置類變數初始值
- 解析:將常量池內的符號引用替換為直接引用
- 初始化:執行類構造器
() 方法
類載入器
類載入過程中的載入操作由類載入去完成。類載入器分為:
- 啟動類載入器/Bootstrap ClassLoader:負責載入JAVA_HOME/lib目錄中的所有類,或者載入由選項-Xbootcalsspath指定的路徑下的類;
- 擴展類載入器/ExtClasLoader:負責載入JAVA_HOME/lib/ext目錄中的所有類型,或者由參數-Xbootclasspath指定路徑中的所有類型;
- 應用程式類載入器/AppClassLoader:負責載入用戶類路徑ClassPath下的所有類型
- 自定義載入器:所有繼承抽象類java.lang.ClassLoader的類載入器
雙親委派模型
雙親委派過程:當一個類載入器收到類載入任務時,立即將任務委派給它的父類載入器去執行,直至委派給最頂層的啟動類載入器為止。如果父類載入器無法載入委派給它的類時,將類載入任務退回給它的下一級載入器去執行。
雙親委派模型最大的好處就是讓Java類同其類載入器一起具備了一種帶優先順序的層次關係。舉個例子來說明下:比如我們要載入頂層的Java類——java.lang.Object類,無論我們用哪個類載入器去載入Object類,這個載入請求最終都會委託給啟動類載入器(Bootstrap ClassLoader),這樣就保證了所有載入器載入的Object類都是同一個類。如果沒有雙親委派模型,就會出現 Wupx::Object 和 Huyx::Object 這樣兩個不同的Object類。
雙親委派模型案例
java.lang.ClassLoader 的 loadClass() 方法
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
本文由部落格一文多發平台 OpenWrite 發布!