JVM 初體驗

     話說現在jdk已經有好多個版本了,官網樓一眼:https://blogs.oracle.com/java-platform-group/the-arrival-of-java-13 已經13了. 以前很少關注專業的官網,學到的都是二手資料,也不知道對不對,還是得多逛逛官網,官網纔是權威(英語渣渣的我,看官網就是悲催)。好了,言歸正傳,今天我們一起來聊聊JVM ,是本人的一點點淺見,還請各位看官大佬多多指教..

1、首先需要了解的就是java中的JDK ,JRE, JVM 這三者的關係?

 這裏引用一個大佬的詳細說明:https://www.cnblogs.com/iskandar/p/8933340.html

相信各位都知道這個內容的。

2、它又是如何轉換的,讓JVM認識的?java源碼是如何進入到JVM中的?

  a. 編譯: javac Test.java ---> Test.class   (源碼 --> 類文件)

cmd -> javac Test.java   這個過程就是通過編譯成類文件的(Test.class)的 ,這是一個怎樣的過程呢?

   Test.java -> 詞法分析器 -> tokens流 -> 語法分析器 -> 語法樹/抽象語法樹 -> 語義分析器 -> 註解抽象語法樹 -> 字節碼生成器 -> Test.class文件 

那麼我們JVM 又是如何看懂這些內容呢? 應該就是有個對應的關係進行轉換的。地址(通過這個地址我們就也知道這個是怎麼來對應的的)https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html

 magic(魔數): cafe babe (固定值)
The  magic  item supplies the magic number identifying the  class  file format; it has the value  0xCAFEBABE . 

0000 0034   對應10進制的52,代表JDK 8中的一個版本

b.類文件到虛擬機(類加載機制

    1. 裝載(Load)查找和導入class文件

   (1)通過一個類的全限定名獲取定義此類的二進制字節流 (2)將這個字節流所代表的靜態存儲結構轉化爲方法區的運行時數據結構 (3)在Java堆中生成一個代表這個類的java.lang.Class對象,作爲對方法區中這些數據的訪問入口

   2.鏈接(Link)

   3. 驗證(Verify)保證被加載類的正確性,如:文件格式驗證、字節碼驗證 、 符號引用驗證 等

   4.準備(Prepare) 爲類的靜態變量分配內存,並將其初始化爲默認值  如:private static int a=10 (在這一步的時候,會先賦值a=0) 

   5.解析(Resolve) 把類中的符號引用轉換爲直接引用 ,通俗的講就是:將這些標識符號轉換成實際的直接引用(實際物理地址)

   6. 初始化(Initialize)將之前準備的 a=0  初始化爲: a=10

見圖:


 

這個地方需要說下:類裝載

在裝載(Load)階段,其中第(1)步:通過類的全限定名獲取其定義的二進制字節流,需要藉助類裝載 器完成,顧名思義,就是用來裝載Class文件的。 (1)通過一個類的全限定名獲取定義此類的二進制字節流 

類加載時,這個地方需要注意下:每次加載都是需要先加載父類,只有父類沒有才找自己(個人理解)。官方說法叫:雙親委派機制

3、裝載完之後,就進入了JVM 了,這裏重點來了,有個概念叫:運行時數據區(Run-Time Data Areas)

說白了就是類文件被類裝載器裝載進來之後,類中的內容(比如變量,常量,方法,對象等這些數 據得要有個去處,也就是要存儲起來,存儲的位置肯定是在JVM中有對應的空間

Heap(堆)  -- (JVM內存的堆內存)針對jvm的只有一個,並且實線程共享的區域(線程是不安全的),主要存放類對象以及數組等。堆內存又分:Yang (Eden,s0(from),s1(to),佔比(8:1:1)爲了更好的處理內存碎片,保證內存空間的連續性),old
Method Area(方法區)  --(JVM內存的非堆內存即永久代) 針對jvm只有一個,並且實線程共享的區域(線程是不安全的),主要存放靜態變量,類信息、常量、即時編譯器編譯後的代碼等。
Run-Time Constant Pool(運行時常量池),屬於線程層面的,存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放
PC Register(程序計數器)在出現多線程時,方便線程之間的切換,主要記錄線程的執行到哪一步等,保存有當前正在執行的JVM指令的地址,爲了線程切換後能夠 恢復到正確的執行位置,每條線程需要有一個獨立的程序計數器(線程私有)。 
Java虛擬機棧 (線程層面),Java棧的區域很小,只有1M,特點是存取速度很快,所以在stack中存放的都是快速執行的任務,基本數據類型的數據,和對象的引用(reference),①以幀爲單位的壓棧或出棧;②通過-Xss來設置, 若不夠會拋出StackOverflowError異常。每一個被線程執行的方法,爲該棧中的棧幀,即每個方法對應一個棧幀。調用一個方法,就會向棧中壓入一個棧幀;一個方法調用完成,就會把該棧幀從棧中彈出
本地方法棧(線程層面),保存native方法進入區域的地址。

未完待續.........

以上如有描述不對的地方,還請各位看官大佬指出,謝謝!!

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