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的類載入器

雙親委派模型

image

雙親委派過程:當一個類載入器收到類載入任務時,立即將任務委派給它的父類載入器去執行,直至委派給最頂層的啟動類載入器為止。如果父類載入器無法載入委派給它的類時,將類載入任務退回給它的下一級載入器去執行。

雙親委派模型最大的好處就是讓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 發布!