最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java虛擬機(jī)工作原理

 更新時(shí)間:2017年03月23日 10:12:20   作者:best.lei  
本文主要介紹了Java虛擬機(jī)的工作原理。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧

首先我想從宏觀上介紹一下Java虛擬機(jī)的工作原理。從最初的我們編寫(xiě)的Java源文件(.java文件)是如何一步步執(zhí)行的,如下圖所示,首先Java源文件經(jīng)過(guò)前端編譯器(javac或ECJ)將.java文件編譯為Java字節(jié)碼文件,然后JRE加載Java字節(jié)碼文件,載入系統(tǒng)分配給JVM的內(nèi)存區(qū),然后執(zhí)行引擎解釋或編譯類(lèi)文件,再由即時(shí)編譯器將字節(jié)碼轉(zhuǎn)化為機(jī)器碼。主要介紹下圖中的類(lèi)加載器和運(yùn)行時(shí)數(shù)據(jù)區(qū)兩個(gè)部分。

類(lèi)加載

類(lèi)加載指將類(lèi)的字節(jié)碼文件(.class)中的二進(jìn)制數(shù)據(jù)讀入內(nèi)存,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆上創(chuàng)建java.lang.Class對(duì)象,封裝類(lèi)在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。類(lèi)加載的最終產(chǎn)品是位于堆中的類(lèi)對(duì)象,類(lèi)對(duì)象封裝了類(lèi)在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu),并且向JAVA程序提供了訪問(wèn)方法區(qū)內(nèi)數(shù)據(jù)結(jié)構(gòu)的接口。如下是類(lèi)加載器的層次關(guān)系圖。

啟動(dòng)類(lèi)加載器(BootstrapClassLoader):在JVM運(yùn)行時(shí)被創(chuàng)建,負(fù)責(zé)加載存放在JDK安裝目錄下的jre\lib的類(lèi)文件,或者被-Xbootclasspath參數(shù)指定的路徑中,并且能被虛擬機(jī)識(shí)別的類(lèi)庫(kù)(如rt.jar,所有的java.*開(kāi)頭的類(lèi)均被Bootstrap ClassLoader加載)。啟動(dòng)類(lèi)無(wú)法被JAVA程序直接引用。

擴(kuò)展類(lèi)加載器(Extension ClassLoader):該類(lèi)加載器負(fù)責(zé)加載JDK安裝目錄下的\jre\lib\ext的類(lèi),或者由java.ext.dirs系統(tǒng)變量指定路徑中的所有類(lèi)庫(kù),開(kāi)發(fā)者也可以直接使用擴(kuò)展類(lèi)加載器。

應(yīng)用程序類(lèi)加載器(AppClassLoader):負(fù)責(zé)加載用戶類(lèi)路徑(Classpath)所指定的類(lèi),開(kāi)發(fā)者可以直接使用該類(lèi)加載器,如果應(yīng)用程序中沒(méi)有定義過(guò)自己的類(lèi)加載器,該類(lèi)加載器為默認(rèn)的類(lèi)加載器。

用戶自定義類(lèi)加載器(User ClassLoader):JVM自帶的類(lèi)加載器是從本地文件系統(tǒng)加載標(biāo)準(zhǔn)的java class文件,而自定義的類(lèi)加載器可以做到在執(zhí)行非置信代碼之前,自動(dòng)驗(yàn)證數(shù)字簽名,動(dòng)態(tài)地創(chuàng)建符合用戶特定需要的定制化構(gòu)建類(lèi),從特定的場(chǎng)所(數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)中)取得java class。

注意如上的類(lèi)加載器并不是通過(guò)繼承的方式實(shí)現(xiàn)的,而是通過(guò)組合的方式實(shí)現(xiàn)的。而JAVA虛擬機(jī)的加載模式是一種委派模式,如上圖中的1-7步所示。下層的加載器能夠看到上層加載器中的類(lèi),反之則不行。類(lèi)加載器可以加載類(lèi)但是不能卸載類(lèi)。說(shuō)了一大堆,還是感覺(jué)需要拿點(diǎn)代碼說(shuō)事。

首先我們先定義自己的類(lèi)加載器MyClassLoader,繼承自ClassLoader,并覆蓋了父類(lèi)的findClass(String name)方法,如下:

public class MyClassLoader extends ClassLoader{
 private String loaderName; //類(lèi)加載器名稱
 private String path = ""; //加載類(lèi)的路徑
 private final String fileType = ".class";
 public MyClassLoader(String name){
  super(); //應(yīng)用類(lèi)加載器為該類(lèi)的父類(lèi)
  this.loaderName = name;
 }
 public MyClassLoader(ClassLoader parent,String name){
  super(parent);
  this.loaderName = name;
 }
 public String getPath(){return this.path;}
 public void setPath(String path){this.path = path;}
 @Override
 public String toString(){return this.loaderName;}
 @Override
 public Class<?> findClass(String name) throws ClassNotFoundException{
  byte[] data = loaderClassData(name);
  return this.defineClass(name, data, 0, data.length);
 }
 //讀取.class文件
 private byte[] loaderClassData(String name){
  InputStream is = null;
  byte[] data = null;
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  try {
   is = new FileInputStream(new File(path + name + fileType));
   int c = 0;
   while(-1 != (c = is.read())){
    baos.write(c);
   }
   data = baos.toByteArray();
  } catch (Exception e) {
   e.printStackTrace();
  } finally{
   try {
    if(is != null)
     is.close();
    if(baos != null)
     baos.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
  return data;
 }
}

我們?nèi)绾卫梦覀兌x的類(lèi)加載器加載指定的字節(jié)碼文件(.class)呢?如通過(guò)MyClassLoader加載C:\\Users\\Administrator\\下的Test.class字節(jié)碼文件,代碼如下所示:

public class Client {
 public static void main(String[] args) {
  // TODO Auto-generated method stub  
  //MyClassLoader的父類(lèi)加載器為系統(tǒng)默認(rèn)的加載器AppClassLoader
  MyClassLoader myCLoader = new MyClassLoader("MyClassLoader");
  //指定MyClassLoader的父類(lèi)加載器為ExtClassLoader
  //MyClassLoader myCLoader = new MyClassLoader(ClassLoader.getSystemClassLoader().getParent(),"MyClassLoader");
  myCLoader.setPath("C:\\Users\\Administrator\\");
  Class<?> clazz;
  try {
   clazz = myCLoader.loadClass("Test");
   Field[] filed = clazz.getFields(); //獲取加載類(lèi)的屬性字段
   Method[] methods = clazz.getMethods(); //獲取加載類(lèi)的方法字段
   System.out.println("該類(lèi)的類(lèi)加載器為:" + clazz.getClassLoader());
   System.out.println("該類(lèi)的類(lèi)加載器的父類(lèi)為:" + clazz.getClassLoader().getParent());
   System.out.println("該類(lèi)的名稱為:" + clazz.getName());
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

運(yùn)行時(shí)數(shù)據(jù)區(qū)

字節(jié)碼的加載第一步,其后分別是認(rèn)證、準(zhǔn)備、解析、初始化,那么這些步驟又具體做了哪些工作,以及他們會(huì)對(duì)運(yùn)行時(shí)數(shù)據(jù)區(qū)纏身什么影響呢?如下圖所示:

如下我們將介紹運(yùn)行時(shí)數(shù)據(jù)區(qū),主要分為方法區(qū)、Java堆、虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器。其中方法區(qū)和Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,而虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器是線程私有的內(nèi)存區(qū)。

Java堆:Java堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊,被進(jìn)程的所有線程共享,在虛擬機(jī)啟動(dòng)時(shí)被創(chuàng)建。該區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存,隨著JIT編譯器的發(fā)展與逃逸分支技術(shù)逐漸成熟,棧上分配、標(biāo)量替換等優(yōu)化技術(shù)使得對(duì)象在堆上的分配內(nèi)存變得不是那么“絕對(duì)”。Java堆是垃圾收集器管理的主要區(qū)域。由于現(xiàn)在的收集器基本都采用分代收集算法,所以Java堆中還可以分為老年代和新生代(Eden、From Survivor、To Survivor)。根據(jù)Java虛擬機(jī)規(guī)范,Java堆可以處于物理上不連續(xù)的內(nèi)存空間,只要邏輯上連續(xù)即可。該區(qū)域的大小可以通過(guò)-Xmx和-Xms參數(shù)來(lái)擴(kuò)展,如果堆中沒(méi)有內(nèi)存完成實(shí)例分配,并且堆也無(wú)法擴(kuò)展,將會(huì)拋出OutOfMemoryError異常。

方法區(qū):用于存儲(chǔ)被Java虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。不同于Java堆的是,Java虛擬機(jī)規(guī)范對(duì)方法區(qū)的限制非常寬松,可以選擇不實(shí)現(xiàn)垃圾收集。但并非數(shù)據(jù)進(jìn)入了方法區(qū)就“永久”存在了,這區(qū)域內(nèi)存回收目標(biāo)主要是針對(duì)常量池的回收和對(duì)類(lèi)型的卸載。如果該區(qū)域內(nèi)存不足也會(huì)拋出OutOfMemoryError異常。

常量池:這個(gè)名詞可能大家也經(jīng)常見(jiàn),它是方法區(qū)的一部分。Class文件除了有類(lèi)的版本、字段、方法、接口等描述信息外,還有一項(xiàng)信息就是常量池,用于存放編譯期生成的各種字面量和符號(hào)引用。Java虛擬機(jī)運(yùn)行期間,也可能將新的常量放入常量池(如String類(lèi)的intern()方法)。

虛擬機(jī)棧:線程私有,生命周期與線程相同。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法在執(zhí)行時(shí)都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。每個(gè)方法從調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過(guò)程。如果請(qǐng)求的站深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常,虛擬機(jī)棧在動(dòng)態(tài)擴(kuò)展時(shí)如果無(wú)法申請(qǐng)到足夠的內(nèi)存,就會(huì)拋出OutOfMemoryError異常。

本地方法棧:與虛擬機(jī)棧類(lèi)似,不過(guò)虛擬機(jī)棧是為虛擬機(jī)執(zhí)行Java方法(字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)。該區(qū)域同樣會(huì)報(bào)StackOverflowError和OutOfMemoryError異常。

程序計(jì)數(shù)器:一塊較小的內(nèi)存空間,可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。字節(jié)碼解釋器工作時(shí)就是通過(guò)改變這個(gè)計(jì)數(shù)器的值來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)計(jì)數(shù)器完成。如果線程正在執(zhí)行一個(gè)Java方法,計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址,如果正在執(zhí)行的是Native方法,這個(gè)計(jì)數(shù)器值為空。此內(nèi)存區(qū)域是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒(méi)有規(guī)定任何OutOfMemoryError情況的區(qū)域。

寫(xiě)了這么多,感覺(jué)還是少一個(gè)例子。通過(guò)最簡(jiǎn)單的一段代碼解釋一下,程序在運(yùn)行時(shí)數(shù)據(jù)區(qū)個(gè)部分的變化情況。

public class Test{
  public static void main(String[] args){
   String name = "best.lei";
   sayHello(name);
  }
  public static void sayHello(String name){
   System.out.println("Hello " + name);
  }
}

通過(guò)編譯器將Test.java文件編譯為T(mén)est.class,利用javap -verbose Test.class對(duì)編譯后的字節(jié)碼進(jìn)行分析,如下圖所示:

我們?cè)诳纯催\(yùn)行時(shí)數(shù)據(jù)區(qū)的變化:

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • SpringBoot整合Kafka工具類(lèi)的詳細(xì)代碼

    SpringBoot整合Kafka工具類(lèi)的詳細(xì)代碼

    Kafka是一種高吞吐量的分布式發(fā)布訂閱消息系統(tǒng),它可以處理消費(fèi)者在網(wǎng)站中的所有動(dòng)作流數(shù)據(jù),這篇文章主要介紹了SpringBoot整合Kafka工具類(lèi)的代碼詳解,需要的朋友可以參考下
    2022-09-09
  • Spring Hibernate實(shí)現(xiàn)分頁(yè)功能

    Spring Hibernate實(shí)現(xiàn)分頁(yè)功能

    這篇文章主要為大家詳細(xì)介紹了Spring Hibernate實(shí)現(xiàn)分頁(yè)功能的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 簡(jiǎn)單闡述一下Java集合的概要

    簡(jiǎn)單闡述一下Java集合的概要

    今天給大家?guī)?lái)的文章是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java集合的概要展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • SpringBatch數(shù)據(jù)寫(xiě)入實(shí)現(xiàn)

    SpringBatch數(shù)據(jù)寫(xiě)入實(shí)現(xiàn)

    Spring Batch通過(guò)ItemWriter接口及其豐富的實(shí)現(xiàn),提供了強(qiáng)大的數(shù)據(jù)寫(xiě)入能力,本文主要介紹了SpringBatch數(shù)據(jù)寫(xiě)入實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-04-04
  • springboot配置mysql連接的實(shí)例代碼

    springboot配置mysql連接的實(shí)例代碼

    這篇文章主要介紹了springboot配置mysql連接的實(shí)例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Java8與Scala中的Lambda表達(dá)式深入講解

    Java8與Scala中的Lambda表達(dá)式深入講解

    這篇文章主要給大家介紹了關(guān)于Java8與Scala中Lambda表達(dá)式的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • idea運(yùn)行java的配置詳細(xì)教程(包含maven,mysql下載配置)

    idea運(yùn)行java的配置詳細(xì)教程(包含maven,mysql下載配置)

    程序員們?cè)陂_(kāi)發(fā)的時(shí)候,一定會(huì)用到Intellij?IDEA這個(gè)集成開(kāi)發(fā)環(huán)境,這篇文章主要給大家介紹了關(guān)于idea運(yùn)行java的配置(包含maven,mysql下載配置)的相關(guān)資料,需要的朋友可以參考下
    2024-05-05
  • java?SpringBootWeb請(qǐng)求響應(yīng)舉例詳解

    java?SpringBootWeb請(qǐng)求響應(yīng)舉例詳解

    SpringBoot是一種整合Spring技術(shù)棧的方式(或者說(shuō)是框架),同時(shí)也是簡(jiǎn)化Spring的一種快速開(kāi)發(fā)的腳手架,這篇文章主要給大家介紹了關(guān)于java?SpringBootWeb請(qǐng)求響應(yīng)的相關(guān)資料,需要的朋友可以參考下
    2024-05-05
  • Spring Security賬戶與密碼驗(yàn)證實(shí)現(xiàn)過(guò)程

    Spring Security賬戶與密碼驗(yàn)證實(shí)現(xiàn)過(guò)程

    這篇文章主要介紹了Spring Security賬戶與密碼驗(yàn)證實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-03-03
  • 使用jmx?exporter采集kafka指標(biāo)示例詳解

    使用jmx?exporter采集kafka指標(biāo)示例詳解

    這篇文章主要為大家介紹了使用jmx?exporter采集kafka指標(biāo)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11

最新評(píng)論

淳安县| 蓬莱市| 文昌市| 南江县| 平武县| 陕西省| 车致| 抚顺县| 靖江市| 辛集市| 阿城市| 秦皇岛市| 望谟县| 怀集县| 寿宁县| 麦盖提县| 柳州市| 吉安市| 秦皇岛市| 宣威市| 确山县| 灵石县| 德庆县| 铁岭县| 南漳县| 开鲁县| 陕西省| 大同县| 商河县| 元朗区| 大埔县| 皮山县| 龙口市| 双桥区| 贡山| 彭泽县| 遂溪县| 尼玛县| 龙胜| 平谷区| 乳山市|