日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM 类加载机制深入浅出

發布時間:2024/9/30 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM 类加载机制深入浅出 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

從類被加載到虛擬機內存中開始,到卸御出內存為止,它的整個生命周期分為7個階段,加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸御(Unloading)。其中驗證、準備、解析三個部分統稱為連接。
7個階段發生的順序如下:

1. 加載

  • 通過一個類的全限定名來獲取定義此類的二進制字節流。
  • 將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構。
  • 在內存中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口。
    注意:JVM中的ClassLoader類加載器加載Class發生在此階段
  • 2. 驗證

    2.1 文件格式的驗證

  • 主要驗證字節流是否符合Class文件格式的規范,如果符合則把字節流加載到方法區中進行存儲。
  • 文件頭、主次版本驗證等等
  • 2.2 元數據驗證

    主要對字節碼描述的信息進行語義分析,保證其描述符合Java語言的要求。
    1. 類是否有父類
    2. 是否繼承了不允許被繼承的類(final修飾過的類)
    3. 如果這個類不是抽象類,是否實現其父類或接口中所有要求實現的方法
    4. 類中的字段、方法是否與父類產生矛盾(如:覆蓋父類final類型的字段,或者不符合個則的方法)

    2.3 字節碼驗證

    最復雜的一個階段。主要目的是通過數據量和控制流分析,確定程序語義是合法的,符合邏輯的。
    保證被校驗類的方法在運行時不會做出危害虛擬機安全的事件。

    2.4 符號引用驗證

    符號引用中通過字符串描述的全限定名是否能找到對應的類。
    在指定類中是否存在符合方法的字段描述符以及簡單名稱所描述的方法和字段。
    符號引用中的類、字段、方法的訪問性(private、protected、public、default)是否可被當前類訪問。

    3、準備

    準備階段正式為類變量分配內存并設置初始值階段。
    public static int value=123; 初始后為 value=0;
    對于static final類型,在準備階段會被賦予正確的值
    public static final value=123;初始化為 value=123;

    如果是boolean值默認賦值為:false
    如果是對象引用默認賦值為:null

    **注意:
    只設置類中的靜態變量(方法區中),不包括實例變量(堆內存中),實例變量是在對象實例化的時候初始化分配值的**

    4、解析

    解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程。
    1. 符號引用:簡單的理解就是字符串,比如引用一個類,java.util.ArrayList 這就是一個符號引用,字符串引用的對象不一定被加載。
    2. 直接引用:指針或者地址偏移量。引用對象一定在內存(已經加載)。

    5、初始化

  • 執行類構造器
  • 初始化靜態變量、靜態塊中的數據等(一個類加載器只會初始化一次)
  • 子類的調用前保證父類的被調用
    **注意:
    是線程安全的,執行的線程需要先獲取鎖才能進行初始化操作,保證只有一個線程能執行(利用此特性可以實現線程安全的懶漢單例模式)。**
  • 什么是類裝載器ClassLoader

  • ClassLoader是一個抽象類
  • ClassLoader的實例將讀入Java字節碼將類裝載到JVM中
  • ClassLoader可以定制,滿足不同的字節碼流獲取方式
  • ClassLoader負責類裝載過程中的加載階段。
  • JVM中的類加載器

  • 啟動類加載器(BootStrap ClassLoader):引導類裝入器是用本地代碼實現的類裝入器,它負責將 jdk中jre/lib下面的核心類庫或-Xbootclasspath選項指定的jar包加載到內存中。由于引導類加載器涉及到虛擬機本地實現細節,開發者無法直接獲取到啟動類加載器的引用,所以不允許直接通過引用進行操作。
  • 擴展類加載器(Extension ClassLoader):擴展類加載器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實現的。它負責將jdk中jre/lib/ext或者由系統變量-Djava.ext.dir指定位置中的類庫加載到內存中。開發者可以直接使用標準擴展類加載器。
  • 系統類加載器(System ClassLoader):系統類加載器是由 Sun的 AppClassLoader(sun.misc.Launcher$AppClassLoader)實現的。它負責將系統類路徑java -classpath或-Djava.class.path變量所指的目錄下的類庫加載到內存中。開發者可以直接使用系統類加載器。
  • 雙親委派模型

    下圖中展示了類加載器直接的關系和雙親委派模型

    從圖中我們發現除啟動類加載器外,每個加載器都有父的類加載器。
    雙親委派機制:如果一個類加載器在接到加載類的請求時,它首先不會自己嘗試去加載這個類,而是把這個請求任務委托給父類加載器去完成,依次遞歸,如果父類加載器可以完成類加載任務,就成功返回;只有父類加載器無法完成此加載任務時,才自己去加載。


    從類的繼承關系來看,ExtClassLoader和AppClassLoader都是繼承URLClassLoader,都是ClassLoader的子類。而BootStrapClassLoader是有C寫的,不再java的ClassLoader子類中。

    **注意:
    從圖中可以看到類加載器間的父子關系不是以繼承的方式實現的,而是以組合關系的方式來復用父加載器的代碼。
    如果一個類加載器收到了類加載的請求,它首先會把這個請求委派給父加載器去完成,每一個層次的類加載器都是如此。 **

    雙親委派模型的好處

    Java類隨著加載它的類加載器一起具備了一種帶有優先級的層次關系。比如,Java中的Object類,它存放在rt.jar之中,無論哪一個類加載器要加載這個類,最終都是委派給處于模型最頂端的啟動類加載器進行加載,因此Object在各種類加載環境中都是同一個類。如果不采用雙親委派模型,那么由各個類加載器自己取加載的話,那么系統中會存在多種不同的Object類。

    破壞雙親委派模型

    案例一

    雙親委派模型的問題:頂層ClassLoader,無法加載底層ClassLoader的類。
    JDK的javax.xml.parsers包中定義了xml解析的類接口
    Service Provider Interface SPI 位于rt.jar 即接口在啟動ClassLoader中。而SPI的實現類,可能由第三方提供,AppClassLoader進行加載。
    解決思路:可以在線程中放入底層的ClassLoader到Thread. setContextClassLoader()中,然后在頂層ClassLoader中使用Thread.getContextClassLoader()獲得底層的ClassLoader進行加載第三方實現。

    案例二

    Tomcat中使用了自定ClassLoader,并且也破壞了雙親委托機制。
    每個應用使用WebAppClassloader進行單獨加載,他首先使用WebAppClassloader進行類加載,如果加載不了再委托父加載器去加載,這樣可以保證每個應用中的類不沖突。每個tomcat中可以部署多個項目,每個項目中存在很多相同的class文件(很多相同的jar包),他們加載到jvm中可以做到互不干擾。

    案例三:

    利用破壞雙親委派來java的類熱部署實現(每次修改類文件,不需要重啟服務)。
    因為一個Class只能被一個ClassLoader加載一次,否則會報java.lang.LinkageError。當我們想要實現代碼熱部署時,可以每次都new一個自定義的ClassLoader來加載新的Class文件。JSP的實現動態修改就是使用此特性實現。

    Class加密實現思路

    ClassLoader加載.class文件的方式不僅限于從jar包中讀取,還可以從種地方讀取,因為ClassLoader加載時需要的是byte[]數組.

    ClassLoader加載Class文件方式:
    1. 從本地系統中直接加載
    2. 通過網絡下載.class文件
    3. 從zip,jar等歸檔文件中加載.class文件
    4. 從專有數據庫中提取.class文件
    5. 將Java源文件動態編譯為.class文件

    加密實現思路:加載Class文件的方式靈活,我們可以自定義ClassLoader,把加密后的Class文件,在加載Class前先進行解密,然后在通過ClassLoader進行加載。

    本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8????
    點擊這里快速進入簡書

    GIT地址:http://git.oschina.net/brucekankan/
    點擊這里快速進入GIT

    總結

    以上是生活随笔為你收集整理的JVM 类加载机制深入浅出的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。