1、JVM之類加載器

1、什麼是JVM

先來看下百度百科的解釋:java

JVM 是 Java Virtual Machine(Java 虛擬機)的縮寫,JVM 是一種用於計算設備的規範,它是一個虛構出來的計算機,是經過在實際的計算機上仿真模擬各類計算機功能來實現的。數據庫

晦澀難懂有沒有,簡單理解就是說虛擬機是物理機的軟件實現。編程

Java 的設計理念是 WORA(Write Once Run Anywhere,一次編寫處處運行)。編譯器將 Java 文件編譯爲 Java .class 文件,而後將 .class 文件輸入到 JVM 中,JVM 執行類文件的加載和執行,最後轉變成機器能夠識別的機器碼進行最終的操做。數組

JVM體系結構圖緩存

2、類加載的過程

一、加載安全

加載指的是將類的class文件讀入到內存,併爲之建立一個java.lang.Class對象,也就是說,當程序中使用任何類時,系統都會爲之創建一個java.lang.Class對象。網絡

類的加載由類加載器完成,類加載器一般由JVM提供,這些類加載器也是前面全部程序運行的基礎,JVM提供的這些類加載器一般被稱爲系統類加載器。除此以外,開發者能夠經過繼承ClassLoader基類來建立本身的類加載器。數據結構

經過使用不一樣的類加載器,能夠從不一樣來源加載類的二進制數據,一般有以下幾種來源。jvm

  • 從本地文件系統加載class文件,這是前面絕大部分示例程序的類加載方式。
  • 從JAR包加載class文件,這種方式也是很常見的,前面介紹JDBC編程時用到的數據庫驅動類就放在JAR文件中,JVM能夠從JAR文件中直接加載該class文件。
  • 經過網絡加載class文件。
  • 把一個Java源文件動態編譯,並執行加載。
  • 類加載器一般無須等到「首次使用」該類時才加載該類,Java虛擬機規範容許系統預先加載某些類。

2.連接
當類被加載以後,系統爲之生成一個對應的Class對象,接着將會進入鏈接階段,連接階段負責把類的二進制數據合併到JRE中。類連接又可分爲以下3個階段。佈局

1)驗證:驗證階段用於檢驗被加載的類是否有正確的內部結構,並和其餘類協調一致。Java是相對C++語言是安全的語言,例如它有C++不具備的數組越界的檢查。這自己就是對自身安全的一種保護。驗證階段是Java很是重要的一個階段,它會直接的保證應用是否會被惡意入侵的一道重要的防線,越是嚴謹的驗證機制越安全。驗證的目的在於確保Class文件的字節流中包含信息符合當前虛擬機要求,不會危害虛擬機自身安全。其主要包括四種驗證,文件格式驗證,元數據驗證,字節碼驗證,符號引用驗證。

2)準備:類準備階段負責爲類的靜態變量分配內存,並設置默認初始值。

3)解析:將類的二進制數據中的符號引用替換成直接引用。說明一下:符號引用:符號引用是以一組符號來描述所引用的目標,符號能夠是任何的字面形式的字面量,只要不會出現衝突可以定位到就行。佈局和內存無關。直接引用:是指向目標的指針,偏移量或者可以直接定位的句柄。該引用是和內存中的佈局有關的,而且必定加載進來的。

3.初始化
初始化是爲類的靜態變量賦予正確的初始值,準備階段和初始化階段看似有點矛盾,實際上是不矛盾的,若是類中有語句:private static int a = 10,它的執行過程是這樣的,首先字節碼文件被加載到內存後,先進行連接的驗證這一步驟,驗證經過後準備階段,給a分配內存,由於變量a是static的,因此此時a等於int類型的默認初始值0,即a=0,而後到解析(後面在說),到初始化這一步驟時,才把a的真正的值10賦給a,此時a=10。

3、類加載器ClassLoader

負責加載class文件,class文件在文件開頭由特定的文件標識,將class文件字節碼內容加載到內存中,並將這些內容轉換成方法區中的運行時數據結構而且ClassLoader只負責class文件的加載,至於它是否能夠運行,則由Execution Engine(執行引擎)決定。

四種類加載器

虛擬機自帶的加載器

  • 啓動類加載器(Bootstrap)C++編寫

Bootstrap ClassLoader是由C/C++編寫的,它自己是虛擬機的一部分,因此它並非一個JAVA類,也就是沒法在java代碼中獲取它的引用,JVM啓動時經過Bootstrap類加載器加載rt.jar等核心jar包中的class文件,以前的int.class,String.class都是由它加載。而後呢,咱們前面已經分析了,JVM初始化sun.misc.Launcher並建立Extension ClassLoader和AppClassLoader實例。並將ExtClassLoader設置爲AppClassLoader的父加載器。Bootstrap沒有父加載器,可是它卻能夠做用一個ClassLoader的父加載器。好比ExtClassLoader。這也能夠解釋以前經過ExtClassLoader的getParent方法獲取爲Null的現象

System.out.println(new Object().getClass().getClassLoader());
//這也就是爲何這段代碼打印出結果爲null的緣由
  • 擴展類加載器(Extension)Java編寫

ExtClassLoader稱爲擴展類加載器,主要負責加載Java的擴展類庫,默認加載JAVA_HOME/jre/lib/ext/目錄下的全部jar包或者由java.ext.dirs系統屬性指定的jar包.放入這個目錄下的jar包對AppClassLoader加載器都是可見的(由於ExtClassLoader是AppClassLoader的父加載器,而且Java類加載器採用了委託機制).

  • 應用程序類加載器(AppClassLoader)也叫系統類加載器,加載當前應用的classpath的全部類

AppClassLoader應用類加載器,又稱爲系統類加載器,負責在JVM啓動時,加載來自在命令java中的classpath或者java.class.path系統屬性或者CLASSPATH操做系統屬性所指定的JAR類包和類路徑.

public class AppClassLoaderTest {

    public static void main(String[] args) {
        ClassLoader classLoader = Test.class.getClassLoader();
        System.out.println(classLoader);
        System.out.println(classLoader.getParent());
    }

    private static class Test {

    }
}

//執行結果以下
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742
//從上面的運行結果能夠得知AppClassLoader的父加載器是ExtClassLoader

用戶自定義的加載器

  • Java.lang.ClassLoader的子類,用戶能夠定製類的加載方式

4、類加載機制

JVM的類加載機制主要有以下3種:

  • 全盤負責:所謂全盤負責,就是當一個類加載器負責加載某個Class時,該Class所依賴和引用其餘Class也將由該類加載器負責載入,除非顯示使用另一個類加載器來載入。
  • 雙親委派:所謂的雙親委派,則是先讓父類加載器試圖加載該Class,只有在父類加載器沒法加載該類時才嘗試從本身的類路徑中加載該類。通俗的講,就是某個特定的類加載器在接到加載類的請求時,首先將加載任務委託給父加載器,依次遞歸,若是父加載器能夠完成類加載任務,就成功返回;只有父加載器沒法完成此加載任務時,才本身去加載。
  • 緩存機制:緩存機制將會保證全部加載過的Class都會被緩存,當程序中須要使用某個Class時,類加載器先從緩存區中搜尋該Class,只有當緩存區中不存在該Class對象時,系統纔會讀取該類對應的二進制數據,並將其轉換成Class對象,存入緩衝區中。這就是爲很麼修改了Class後,必須從新啓動JVM,程序所作的修改纔會生效的緣由。

雙親委派機制的做用

一、防止重複加載同一個.class。經過委託去向上面問一問,加載過了,就不用再加載一遍。保證數據安全。 二、保證核心.class不能被篡改。經過委託方式,不會去篡改核心.class,即便篡改也不會去加載,即便加載也不會是同一個.class對象了。不一樣的加載器加載同一個.class也不是同一個Class對象。這樣保證了Class執行安全。

相關文章
相關標籤/搜索