JVM中ClassLoader的學習

JVM中class loaderの學習


1、.class文件和jvm的關係

類的加載

全部的編譯生成的.class文件都會被直接加載到JVM裏面來嗎**(並不**html

首先咱們明確一個概念,.class文件加載到jvm中意味着什麼——類的初始化java

在虛擬機規範中,咱們規定,有且只有五種狀況必須當即對類進行初始化git

  • 建立類的實例(new一個對象)訪問某個類或者接口的靜態變量,對靜態變量賦值,調用類的靜態方法
  • reflection
  • 啓動類(main),直接使用Java.exe命令來運行某個主類(main方法)
  • 動態語言支持
  • 初始化子類,父類也會被初始化

.class的加載是消耗內存的,因此固然不能一次性的把全部的類加載再運行(原本就不快,這樣作不是更慢),程序的base class會徹底加載到jvm裏面來,至於其餘的類,它們都是在須要的時候再加載的,這樣是爲了節省內存開銷。github

怎麼加載

class是經過類的加載器裝在到jvm裏面來的,Java默認有三種類加載器web

  • 引導類加載器(bootstrap class loader):它用來加載 Java 的核心庫,是用原生代碼來實現的,並不繼承自 java.lang.ClassLoader
  • 擴展類加載器(extensions class loader):它用來加載 Java 的擴展庫。Java 虛擬機的實現會提供一個擴展庫目錄。該類加載器在此目錄裏面查找並加載 Java 類。
  • 系統類加載器(system class loader):它根據 Java 應用的類路徑(CLASSPATH)來加載 Java 類。通常來講,Java 應用的類都是由它來完成加載的。能夠經過 ClassLoader.getSystemClassLoader()來獲取它。

未命名文件.png

雙親委派模型apache

若是一個類收到了加載的請求,它首先不會本身加載這個類,而是會把請求委託給父加載器去完成,依次向上。(若是自身完成不了再依次向下,直到拋出ClassNotFound異常)bootstrap

advantage:緩存

防止內存中出現多份一樣的字節碼(從安全性角度來講)tomcat

已經加載過的類,下次還會請求加載嗎?

class loader在成功加載某個類以後,會把獲得的java.lang.Class類的實例緩存起來。若是下次再遇見該類的加載請求,類加載器會直接使用緩存的類的實例,不會再次加載安全

類加載器是什麼?

俄羅斯套娃

類加載器的Java類和全部其餘的Java類同樣,都是要經過類加載器來加載的。

對於開發人員編寫的類加載器來講,父類是加載該類加載器的Java類的類加載器

類加載器樹狀組織結構示意圖

2、類的加載過程

加載器加載到jvm中,接下來其實又分了好幾個步驟

  • 加載,查找並加載類的二進制數據,在Java堆中也建立一個java.lang.Class類的對象
  • 鏈接,鏈接又包含三塊內容:驗證、準備、初始化。
    • 驗證,文件格式、元數據、字節碼、符號引用驗證;
    • 準備,爲類的靜態變量分配內存,並將其初始化爲默認值;
    • 解析,把類中的符號引用轉換爲直接引用
  • 初始化,爲類的靜態變量賦予正確的初始值。

未命名文件 (1).png

3、類加載器和web容器

對於運行在 Java EE™容器中的 Web 應用來講,類加載器的實現方式與通常的 Java 應用有所不一樣。不一樣的 Web 容器的實現方式也會有所不一樣。以 Apache Tomcat 來講,每一個 Web 應用都有一個對應的類加載器實例。該類加載器也使用代理模式,所不一樣的是它是首先嚐試去加載某個類,若是找不到再代理給父類加載器。這與通常類加載器的順序是相反的。這是 Java Servlet 規範中的推薦作法,其目的是使得 Web 應用本身的類的優先級高於 Web 容器提供的類。這種代理模式的一個例外是:Java 核心庫的類是不在查找範圍以內的。這也是爲了保證 Java 核心庫的類型安全

In a Java environment, class loaders are arranged in a parent-child tree. Normally, when a class loader is asked to load a particular class or resource, it delegates the request to a parent class loader first, and then looks in its own repositories only if the parent class loader(s) cannot find the requested class or resource. Note, that the model for web application class loaders differs slightly from this, as discussed below, but the main principles are the same.

When Tomcat is started, it creates a set of class loaders that are organized into the following parent-child relationships, where the parent class loader is above the child class loader:

Bootstrap
          |
       System
          |
       Common
       /     \
  Webapp1   Webapp2 ...

Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:

Bootstrap classes of your JVM /WEB-INF/classes of your web application /WEB-INF/lib/.jar of your web application System class loader classes (described above) Common class loader classes (described above)

If the web application class loader is configured with <Loader delegate="true"/> then the order becomes:*

Bootstrap classes of your JVM System class loader classes (described above) Common class loader classes (described above) /WEB-INF/classes of your web application /WEB-INF/lib/.jar of your web application

絕大多數狀況下,Web 應用的開發人員不須要考慮與類加載器相關的細節。下面是幾條簡單的原則:

  • 每一個 Web 應用本身的 Java 類文件和使用的庫的 jar 包,分別放在 WEB-INF/classesWEB-INF/lib目錄下面。
  • 多個應用共享的 Java 類文件和 jar 包,分別放在 Web 容器指定的由全部 Web 應用共享的目錄下面。
  • 當出現找不到類的錯誤時,檢查當前類的類加載器和當前線程的上下文類加載器是否正確。

ps.用的圖牀掛了,你們先將就着看下,後續再改

Demo

跟着博客作的一個ClassLoader小demo https://github.com/JhinQaQ/Classloader

參考資料

Java虛擬機底層原理知識總結 https://github.com/doocs/jvm

tomcat7.0 ClassLoader http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html

深刻探討Java類加載器 https://www.ibm.com/developerworks/cn/java/j-lo-classloader/

Java類加載器的使用場景有哪些?https://www.zhihu.com/question/46719811

相關文章
相關標籤/搜索