JVM核心知識-類加載機制

JVM中類的生命週期包括7個階段,加載、準備、驗證、解析、初始化、使用、卸載。其中準備、驗證、解析被歸爲鏈接階段。image.pngjava

加載

jvm在這個階段完成的工做數據結構

  • 經過類名獲取類的二進制字節流
  • 將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構
  • 在堆中生成一個表明該類的java.lang.class對象,做爲訪問類在方法區中數據的入口

在這個階段開發者能夠控制二進制字節流的獲取,也就是能夠經過自定義的類加載器作本身定製化的操做。jvm

驗證

顧名思義,驗證被加載的類的正確性。ide

  • 文件格式驗證:驗證字節流是否符合Class文件格式的規範;例如:是否以 0xCAFEBABE開頭
  • 元數據驗證:對字節碼描述的信息進行語義分析,以保證其描述的信息符合Java語言規範的要求
  • 字節碼驗證:經過數據流和控制流分析,肯定程序語義是合法的、符合邏輯的。
  • 符號引用驗證:確保解析動做能正確執行

準備

爲類的 靜態變量分配內存,並將其初始化爲默認值spa

  • 只分配靜態變量內存
  • 初始化默認值是類型的默認值(即int:0、boolean:false...),不是代碼顯示設置的初始值
  • 若是是final static修飾的變量則會賦值爲代碼中的初始值(即:final static int val=3,這時val賦值爲3,而不是0)

解析

把類中的符號引用轉換爲直接引用符號引用就是一組符號來描述目標(例如:ArrayList)。直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄。指針

初始化

類變量的初始化code

  • 定義類變量時初始化
  • 靜態代碼塊初始化

觸發類初始化的場景對象

  • 建立類實例,即new對象
  • 訪問靜態變量
  • 訪問靜態方法
  • 反射調用(即Class.forName("com.xxx.Obj"),Obj類被初始化)
  • 子類被初始化則父類被初始化

類加載器

  • 啓動類加載器(BootStrap ClassLoader):負責加載jrelib下或者-Xbootclasspath 參數指定的路徑下的能被jvm識別的類庫。開發者沒法直接使用
  • 拓展類加載器(Extension ClassLoader):sun.misc.Launcher$ExtClassLoader,它負責加載 jrelibext目錄中,或者由 java.ext.dirs系統變量指定的路徑中的全部類庫。開發者能夠直接使用。
  • 應用類加載器(Application ClassLoader):sun.misc.Launcher$AppClassLoader,它負責加載用戶類路徑(ClassPath)所指定的類。開發者能夠直接使用
  • 自定義類加載器(Custom ClassLoader):用戶能夠自定義類加載器

雙親委派模型

image.png

雙親委派模型的實現,當一個類加載器須要加載類時,會把這個任務委派給父級類加載器,依次向上,倒頂層啓動類加載器爲止,若是父級沒法加載,再本身處理加載。雙親委派模型的好處是,保證同一類環境中只有一個相同的類。也就是說JVM中判斷是不是同一個類的條件是,是否相同的類加載器,類自己相同。代碼示例:生命週期

public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 使用ClassLoaderTest的類加載器加載本類

        Object obj1 = ClassLoaderTest.class.getClassLoader().loadClass("com.ognice.ClassLoaderTest").newInstance();
        System.out.println(obj1.getClass().getClassLoader());
        System.out.println(obj1 instanceof ClassLoaderTest);

        // 使用自定義類加載器加載本類
        ClassLoader customClassLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                System.out.println("custom classloader loading " + name);
                String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                InputStream stream = getClass().getResourceAsStream(fileName);
                if (stream == null) {
                    return super.loadClass(name);
                }
                try {
                    byte[] b = new byte[stream.available()];
                    stream.read(b);
                    return defineClass(name, b, 0, b.length);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // 父級找class
                return super.loadClass(name);
            }
        };
        Object obj2 = customClassLoader.loadClass("com.ognice.ClassLoaderTest").newInstance();
        System.out.println(obj2.getClass().getClassLoader());
        System.out.println(obj2 instanceof ClassLoaderTest);
    }

}

執行結果內存

sun.misc.Launcher$AppClassLoader@18b4aac2
true
custom classloader loading com.ognice.ClassLoaderTest
custom classloader loading java.lang.Object
custom classloader loading java.lang.ClassLoader
custom classloader loading com.ognice.ClassLoaderTest$1
com.ognice.ClassLoaderTest$1@277c0f21
false
相關文章
相關標籤/搜索