1-JVM基礎

1-JVM基礎

java源碼文件,通過javac 轉換成class文件。

找到.java文件

詞法分析器

tokens流

語法分析器

語義分析器

字節碼生成器

轉成.class文件

  • 裝載

    1. 根據全限定路徑名尋找class文件,轉換成二進制流。通過ClassLoder.load(String name)(類裝載器,name:全限定路徑名)不同路徑下的類,設置不同路徑的類裝載器。

      1. Bootstrap ClassLoader(根裝載器由C語言編寫):加載 $JAVA_HOME 中的 jar/lib/rt.jar 裏所有的class或 Xbootclassoath 選項指定的jar包

      2. Extension ClassLoader:加載Java平臺中擴展功能的一些jar包,包括 $JAVA_HOMEjar/lib/*.jar-Djava.ext.dirs 指定目錄下的 jar

      3. App ClassLoader:加載classpath中指定的jar包及 Djava.class.path 所指定目錄下的類和 jar

      4. Custom ClassLoader(自定義裝載器改變裝載原則,如Tomcat打破雙親委派機制):通過 java.lang.ClassLoader 的子類自定義加載class,屬於應用程序根據自身需要自定義的 ClassLoader,如 TomcatJBoss 都會根據j2ee規範自行實現 ClassLoader

    2. 需要把類文件靜態存儲結構裏面對應的內容存儲到JVM裏面(方法區的運行時數據結構)

      代碼裏一段方法不宜過長(阿里規範中提到一段方法不應超過80行)。方法存到JVM裏的棧幀。內容一旦超過一定行數或者過長時,JVM就會從編譯性改變爲解釋性,從而導致性能下降。

    3. java.lang.Class對象存儲到堆內存

  • 鏈接

    1. 驗證

      保證被加載的正確性。驗證class文件中的cafe babe。注:class文件中,已cafe babe爲開頭的是java文件。

    2. 準備

      爲類的靜態變量分配內存。如:private static int a = 3;//爲a分配內存,並且將a初始化默認值,默認值:a=0

    3. 解析

      將類中的符號引用轉換爲直接引用。靜態的轉換。

      符號引用:就是class文件中的內容,符合JVM規範的內容,JVM認識的語言。

      直接引用:在Java進程中能夠代表真實含義的。JVM更底層,計算機能夠認識的語言,並且操作的。比方說爲某個靜態變量分配了真實的內存。

  • 初始化

    對類的靜態變量,進行正真的初始化。就是將上一步中的準備過程中的private static int a = 3;//爲a分配內存,並且將a初始化默認值,默認值:a=0。將3正真的賦值 a = 3。

JVM運行時劃分的區域:

程序最小單位是進程(數據不安全進程內的數據會被該進程內所有的線程共享),進程包含多個線程。

線程是進程最小的執行單位。

棧:只要符合棧結構,都遵循先進後出的原則

  • 方法區 Method Area(進程)、非堆:類信息【類的創建時間、作者、元數據(數據描述信息)】、常量【final】、靜態變量【static】、即時編譯器編譯後的代碼。裏面存儲的是一些。類類型加載的東西(也就是反射中的.class之後的Class),用於存儲已經被虛擬機加載的類的信息、常量、靜態變量等。與堆一樣,是被線程共享的內存區域,要注意線程安全問題。方法區邏輯上屬於堆的一部分。如果存儲數據大小超過了比方說1個G就會報OutOfMemoryError(OOM)異常。

  • 堆 Heap(進程):代表某個類的java.lang.Class對象。存儲對象、String、數組。如果存儲數據大小超過了比方說1個G就會報OutOfMemoryError(OOM)異常。

  • Java虛擬機棧(線程):一個線程當中會有一個私有Java虛擬機棧。生命週期是與線程綁定在一起。存儲Java方法。

    在Java方法中如何去調用C語言的方法,通過動態鏈接去調用完成。

  • 本地方法棧(線程):存儲C語言方法。

  • 棧幀(Java虛擬機棧、本地方法棧)Frame:代表是方法的執行。一個棧幀被創建就表示一個方法被執行,方法壓棧先進後出。

    //僞代碼1
    a(){
        b();
    }
    b(){
        c();
    }
    c(){
        
    }
    //先進行壓棧
    //先往Java虛擬機中壓棧存入a(),之後是b(),在之後是c()。
    //之後是出棧
    //在c()方法執行完之後先出,b()執行完再出,最後是a()執行完再出。
    //先進後出的概念。
    
    //僞代碼2
    a(){
        a();
    }
    //如果遞歸一直調用自己,超出棧的長度或深度,就會報StackOverflowError(棧溢出)。同理如果一個方法內部的調用鏈非常長或深的話也一樣會報StackOverflowError(棧溢出)。
    
    1. 局部變量表:存儲方法中的局部變量

    2. 操作數棧:棧結構,用來描述運算過程當中數據暫時的存儲位置

      //僞代碼.java文件
      public static int calc(int op1,int op2){
          op1 = 3;
          int result = op1 + op2;
          return result;
      }
      //.java文件的.class文件翻譯的JVM字節碼。
      public static int calc(int op1,int op2);
      Code:
      0:iconst_3 // 將3放到操作數棧中
      //局部變量下標:如果是類級別方法【static修飾的方法】下標是從0開始;如果是實例方法下標從1開始,0標識的是這個實例,保留給當前對象的引用this。
      1:istore_0 //將操作數佔中的3賦值給局部變量表中的局部變量
      2:iload_0 //將局部變量0值放到操作數棧中
      3:iload_1 //
      4:iadd
      5:istore_2
      6:iload_2
      7:ireturn
      
    3. 動態鏈接:符號引用轉換爲直接引用**。動態的轉換。比方說:一個方法調用某個接口或抽象類,這時是不知道這個方法內部具體實現的,只有等到程序運行時才能知道具體是調用了哪個子類或實現類的方法。

    4. 正常或異常方法的返回:

  • 程序計數器(線程):是一塊較小的內存空間,它可以看做是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型裏(僅是概念模型,各種虛擬機可能會通過一些更高效的方式去實現),字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。

JAVA 對象內存佈局

對象頭:

Mark Word:一系列的標記爲(哈希碼,分代年齡,鎖狀態標誌等)64位系統:8字節

Class Pointer:指向對象對應的類元數據的內存地址 64位系統:8字節

Length數組對象特有:數組長度 4字節

實例數據:

包含了對象的所有成員變量,大小由各個變量類型決定

boolean和byte:1字節

short和char:2字節

int和float:4字節

long和double:8字節

reference:8字節(64位系統)

對齊填充:

爲了保證對象的大小爲8字節的整數倍,會進行填充字節
趙小胖個人博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章