日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
竟然還有人沒(méi)搞懂JVM類(lèi)加載器?一文徹底明白

竟然還有人沒(méi)搞懂 JVM 類(lèi)加載器?一文徹底明白

作者:Java高級(jí)架構(gòu)師阿谷 2019-10-28 10:19:27

云計(jì)算

虛擬化 在Java面試中,在考察完項(xiàng)目經(jīng)驗(yàn)、基礎(chǔ)技術(shù)后,我會(huì)根據(jù)候選人的特點(diǎn)進(jìn)行知識(shí)深度的考察,如果候選人簡(jiǎn)歷上有寫(xiě)JVM(Java虛擬機(jī))相關(guān)的東西,那么我常常會(huì)問(wèn)一些JVM的問(wèn)題。

創(chuàng)新互聯(lián)建站專(zhuān)注于企業(yè)成都全網(wǎng)營(yíng)銷(xiāo)、網(wǎng)站重做改版、涪陵網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5高端網(wǎng)站建設(shè)、商城網(wǎng)站制作、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為涪陵等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。

寫(xiě)在前面

在Java面試中,在考察完項(xiàng)目經(jīng)驗(yàn)、基礎(chǔ)技術(shù)后,我會(huì)根據(jù)候選人的特點(diǎn)進(jìn)行知識(shí)深度的考察,如果候選人簡(jiǎn)歷上有寫(xiě)JVM(Java虛擬機(jī))相關(guān)的東西,那么我常常會(huì)問(wèn)一些JVM的問(wèn)題。JVM的類(lèi)加載機(jī)制是一個(gè)很經(jīng)典的知識(shí)點(diǎn),圍繞這個(gè)知識(shí)點(diǎn)可以有下面這些難度不同的問(wèn)題。

  1. 簡(jiǎn)單講下JVM中的類(lèi)加載過(guò)程
  2. JVM中的類(lèi)加載和卸載的時(shí)機(jī)?
  3. 如何理解JVM中不同類(lèi)加載器的概念和作用?
  4. 簡(jiǎn)單講下JVM中的雙親委派模型?
  5. 什么情況下會(huì)破壞雙親委派模型?為什么?可否舉個(gè)例子?
  6. Tomcat中的類(lèi)加載機(jī)制有了解嗎?為什么這么設(shè)計(jì)?
  7. 實(shí)際開(kāi)發(fā)中有遇到哪些類(lèi)加載器相關(guān)的問(wèn)題?你又是如何解決的?
  8. JVM之上的弱類(lèi)型語(yǔ)言例如Groovy是如何實(shí)現(xiàn)?簡(jiǎn)單講下動(dòng)態(tài)類(lèi)加載機(jī)制?

在接下來(lái)的幾篇文章,我將跟讀者一起重新梳理一遍類(lèi)加載器的相關(guān)知識(shí),爭(zhēng)取能夠妥善解答上面列出的這些問(wèn)題。

基本概念篇

類(lèi)的加載和卸載

JVM是虛擬機(jī)的一種,它的指令集語(yǔ)言是字節(jié)碼,字節(jié)碼構(gòu)成的文件是class文件。平常我們寫(xiě)的Java文件,需要編譯為class文件才能交給JVM運(yùn)行??梢赃@么說(shuō):C語(yǔ)言代碼——>二進(jìn)制文件——>計(jì)算機(jī)硬件,就相當(dāng)于Java代碼——>字節(jié)碼文件——>JVM。JVM將指定的class文件讀取到內(nèi)存里,并運(yùn)行該class文件里的Java程序的過(guò)程,就稱(chēng)之為類(lèi)的加載;反之,將某個(gè)class文件的運(yùn)行時(shí)數(shù)據(jù)從JVM中移除的過(guò)程,就稱(chēng)之為類(lèi)的卸載。

class文件的運(yùn)行時(shí)數(shù)據(jù)就是C++對(duì)象,也稱(chēng)為kclass對(duì)象,這些運(yùn)行時(shí)數(shù)據(jù)在JDK7之前是放在永久代(PermGen),JDK8之后則放在元空間(Metaspace)。

類(lèi)的生命周期

Java類(lèi)從被虛擬機(jī)加載開(kāi)始,到卸載出內(nèi)存為止,它的整個(gè)生命周期包括:加載(Loading)、驗(yàn)證(Verification)、準(zhǔn)備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸載(Unloading)7個(gè)階段;其中驗(yàn)證、準(zhǔn)備和解析又統(tǒng)稱(chēng)為連接(Linking)階段。

類(lèi)的加載的時(shí)機(jī)

虛擬機(jī)規(guī)范并未嚴(yán)格規(guī)定類(lèi)加載的時(shí)機(jī),跟具體的JVM虛擬機(jī)有關(guān)。類(lèi)加載的最佳時(shí)機(jī)是解析Java字節(jié)碼類(lèi)文件中常量池符號(hào)的時(shí)候,Class.forName()、ClassLoader.loadClass()、反射API和JNI_FindClass都可以觸發(fā)類(lèi)加載,Hot JVM自身啟動(dòng)的時(shí)候也會(huì)觸發(fā)類(lèi)加載。

通過(guò)JVM參數(shù)中加-verbose:class,可以在應(yīng)用啟動(dòng)的時(shí)候打印類(lèi)加載的過(guò)程,如下圖所示:

  1. 初始化這個(gè)階段,JVM虛擬機(jī)給出了5種必須對(duì)類(lèi)進(jìn)行“初始化”的情況
  2. 使用new關(guān)鍵字實(shí)例化對(duì)象的時(shí)候、讀取或設(shè)置一個(gè)類(lèi)的靜態(tài)字段的時(shí)候、調(diào)用一個(gè)類(lèi)的靜態(tài)方法的時(shí)候;
  3. 使用java.lang.reflect包的方法對(duì)類(lèi)進(jìn)行反射調(diào)用的時(shí)候,如果類(lèi)沒(méi)有進(jìn)行過(guò)初始化,則要先觸發(fā)其初始化;
  4. 當(dāng)初始化一個(gè)類(lèi)的時(shí)候,如果發(fā)現(xiàn)其父類(lèi)還沒(méi)有被初始化,則要先初始化其父類(lèi);
  5. 當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要指定一個(gè)執(zhí)行的主類(lèi)(包含main方法的那個(gè)類(lèi)),則虛擬機(jī)會(huì)優(yōu)先初始化這個(gè)主類(lèi);
  6. 在JDK1.7以后,動(dòng)態(tài)語(yǔ)言支持的時(shí)候,如果一個(gè)java.lang.invoke.MethodHandle實(shí)例最后的結(jié)果是要執(zhí)行第1種情況的操作,則也要進(jìn)行初始化。

類(lèi)的卸載時(shí)機(jī)

類(lèi)的卸載跟采用的垃圾收集算法有關(guān),在CMS中有兩種方法卸載不必要的類(lèi),一種是等到元空間(Metaspace)滿了的時(shí)候觸發(fā)FGC,另一種是使用跟CMS并發(fā)收集算法類(lèi)似的方式,不過(guò)對(duì)于元空間的閾值和觸發(fā)CMS并發(fā)收集的閾值是獨(dú)立的。更具體的可以參考之前的文章:CMS學(xué)習(xí)筆記。在這里,我們只需要記住,JVM中一個(gè)類(lèi)的卸載要滿足下面這3個(gè)條件:

  1. 該類(lèi)所有的實(shí)例對(duì)象都已被回收;
  2. 該類(lèi)的類(lèi)加載器對(duì)象已經(jīng)被回收;
  3. 該類(lèi)對(duì)應(yīng)的java.lang.Class對(duì)象沒(méi)有在任何地方被引用,無(wú)法在任何地方通過(guò)反射訪問(wèn)該類(lèi)的方法。

類(lèi)加載器的作用

類(lèi)的加載是需要類(lèi)加載器完成的,但是類(lèi)加載器在JVM中的作用可不止這些。在JVM中,一個(gè)類(lèi)的唯一性是需要這個(gè)類(lèi)本身和類(lèi)加載一起才能確定的,每個(gè)類(lèi)加載器都有一個(gè)獨(dú)立的命名空間。

不同的類(lèi)加載器,即使是同一個(gè)類(lèi)字節(jié)碼文件,最后再JVM里的類(lèi)對(duì)象也不是同一個(gè),下面的代碼展示了這個(gè)結(jié)論:

  
 
 
 
  1. package jvm;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. public class ClassLoaderTest {
  5.  public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException,
  6.  InstantiationException {
  7.  ClassLoader myLoader = new ClassLoader() {
  8.  @Override
  9.  public Class loadClass(String name) throws ClassNotFoundException {
  10.  String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
  11.  InputStream inputStream = getClass().getResourceAsStream(fileName);
  12.  if (inputStream == null) {
  13.  return super.loadClass(name);
  14.  }
  15.  try {
  16.  byte[] b = new byte[inputStream.available()];
  17.  inputStream.read(b);
  18.  return defineClass(name, b, 0, b.length);
  19.  } catch (IOException e) {
  20.  throw new ClassNotFoundException();
  21.  }
  22.  }
  23.  };
  24.  Object obj = myLoader.loadClass("jvm.ClassLoaderTest").newInstance();
  25.  System.out.println(obj.getClass());
  26.  System.out.println(obj instanceof jvm.ClassLoaderTest);
  27.  ClassLoaderTest classLoaderTest = new ClassLoaderTest();
  28.  System.out.println(classLoaderTest.getClass());
  29.  System.out.println(classLoaderTest instanceof jvm.ClassLoaderTest);
  30.  }
  31. }

上述代碼的運(yùn)行結(jié)果是:

可以看出,代碼中使用自定義類(lèi)加載器(myLoader)加載的jvm.ClassLoaderTest類(lèi)和通過(guò)應(yīng)用程序類(lèi)加載器加載的類(lèi)不是同一個(gè)類(lèi)。綜上,類(lèi)加載器在JVM中的作用有:

  1. 將類(lèi)的字節(jié)碼文件從JVM外部加載到內(nèi)存中
  2. 確定一個(gè)類(lèi)的唯一性
  3. 提供隔離特性,為中間件開(kāi)發(fā)者提供便利,例如Tomcat

網(wǎng)站名稱(chēng):竟然還有人沒(méi)搞懂JVM類(lèi)加載器?一文徹底明白
文章來(lái)源:http://m.5511xx.com/article/dpohggj.html