JVM學習筆記(一)

本系列知識80%來自《深入理解Java虛擬機》(周志明)一書,其他部分來自網絡再加上一些自己的理解,如有問題請大家指出。

在跟着書學習虛擬機的過程中,確實非常枯燥,但是學過之後在工作中真的有一種原來如此的感覺(好像有點燥)。希望大家堅持學習下去還有我.

開始~
在我們初次學習java的時候,第一行代碼一般都是“hello world”,如下:

public class First {

	public static void main(String[] args) {

		System.out.println("hi");
	}
}

在javac後,文件夾下會多處First.class文件,然後java First後命令行就會輸出hi。這個過程分爲兩步:首先通過javac命令將First.java文件編譯爲java虛擬機可以執行的First.class文件,然後通過java命令執行First.class中的內容。那麼虛擬機是怎麼通過First.class文件輸出hi的呢?下面來一起研究下

這是First.class文件內容的截圖
在這裏插入圖片描述

我們可以發現.class文件中存儲的是一堆16進制數。如果你的英語像我一樣Good(.),那麼你會發現開頭的“字母”“cafebabe”有些奇怪,如果你的知識像我一樣淵源(…),那麼你會想到與咖啡關係不淺的java在自己的class文件中出現cafe的字樣肯定不是偶然,既然如我優秀的你也發現了這些,那麼恭喜你,看到了java表演的第一個魔術,哦不,是魔數(Magic Number)。

每一個class文件的頭4個字節稱爲魔數,它的唯一作用是確定這個文件是虛擬機可以接受的class文件。

其實後面¥%……&*的內容跟魔數一樣簡單,trust me~

先來看看class文件的結構(圖片截自網絡)
這裏寫圖片描述
class文件嚴格按照上圖中的部分構成。先來講解下圖中所要表達的意思:類型表示該結構的數據類型,class文件格式只有兩種數據類型:無符號數和表。上圖中“u”開頭數字結尾的爲“無符號數”,“info”結尾的爲表。

無符號數就是你腦子中的無符號數,沒有什麼特別的意義,“u”後面的數字表示這個無符號數的長度,單位爲字節,即“u1”表示一個字節的無符號數,“u8”表示8個字節的無符號數。

表就是多個無符號數或者表組成的數據結構;

後面是名稱,我們大概可以通過名稱瞭解該結構,比如magic就是魔數,minor_version是小版本號。

最後是數量,表示該結構出現的次數。比如魔數數量爲1,即出現一次。constant_pool的數量爲constant_pool_count - 1,即constant_pool_count的值減去1。

接下來我們用上圖中的結構來解讀生成的class文件
按照圖中結構,class文件首先是一個四位的無符號數,即魔數,對應class文件中的cafe babe。然後是兩個字節的小版本號和兩個字節的大版本號,分別爲00000034,換算成十進制爲0和50,即小版本爲0,大版本爲1.8(百度一下);

然後是一個兩字節的constant_pool_count意思是常量池中常量的數量(由於常量池中的常量數量是不定的,所有通過這裏指定),001d即29,根據上面的結構圖可知,常量池中的常量爲29 - 1 = 28個。爲什麼要減一?這是因爲001d換算出來的29表示29個位置,即0、1、2、…、27、28,其中0用來表示不引用常量的意思。所以一共有29 - 1 = 28 個常量。

接下來是頗爲麻煩的常量池(麻煩表示常量池雜而多~)。

我們先來看下常量池的項目類型(圖片來自網絡):
在這裏插入圖片描述
這十四種結構中的CONSTANT_MethodHandle_info、CONSTANT_MethodType_info、CONSTANT_InvokeDynamic_info三種是爲了更好的支持動態語言在1.7中新增的。

下面根據上圖來分析下我們的class文件。001d後面的一個字節是0a即十進制的10,也就是上圖中的CONSTANT_Methodref_info:類中方法的符號引用;爲了方便分析,這裏貼一下常量池中常量項的結構表:

在這裏插入圖片描述

根據上表結構所示,後面應該是兩個u2類型的無符號數,分別對應聲明字段的類或者接口描述符CONSTANT_Class_info的索引項和字段描述符CONSTANT_NameAndType的索引項,他們所對應的值分別爲0006和000f即6和15,也就是第六個常量項和第十五個常量項的值(在之前的分析中已經看到這個class文件中一共有28個常量項)。至於他們具體的值,我們一點一點分析;接下來是第二個常量項,09即CONSTANT_Fieldref_info字段的符號引用,它的結構與Methodref一樣,後面是第十六項和第十七項;
第三項#3(下同):
tag:08 CONSTANT_String_info 字符串類型字面量
index:0012 CONSTANT_Utf8_info UTF-8編碼的字符串 即#18
#4
tag:0a(10) CONSTANT_Methodref_info
index:0013 CONSTANT_Class_info #19
index:0014 CONSTANT_NameAndType_info #20
#5
tag:07 CONSTANT_Class_info
index:0015 CONSTANT_Utf8_info #21
#6
tag:07 CONSTANT_Class_info
index:0016 CONSTANT_Utf8_info #22
#7
tag:01 CONSTANT_Utf8_info
length:0006
bytes:3c 69 6e 69 74 3e 翻譯後爲(3c爲“<”)
#8
tag:01 CONSTANT_Utf8_info
length:0003
bytes:282956 ()V
#9
tag:01 CONSTANT_Utf8_info
length:0004
bytes:436f6465 Code
#10
tag:01 CONSTANT_Utf8_info
length:000f
4c696e654e756d6265725461626c65 LineNumberTable
#11
tag:01
length:0004
bytes:6d61696e main
#12
tag:01
length:0016
bytes:285b4c6a6176612f6c616e672f537472696e673b2956 ([Ljava/lang/String;)V
#13
tag:01
length:000a
bytes:536f7572636546696c65 SourceFile
#14
tag:01
length:000a
bytes:46697273742e6a617661 First.java
#15
tag:0c CONSTANT_NameAndType_info
index:0007 #7
index:0008 #8
#16
tag:07
index:0017 #23
#17
tag:0c CONSTANT_NameAndType_info
index:0018 #7
index:0019 #8
#18
tag:01
length:0002
bytes:6869 hi
#19
tag:07
index:001a #26
#20
tag:0c
index:001b #27
index:001c #28
#21
tag:01
length:0005
bytes:4669727374 First
#22
tag:01
length:0010
bytes:6a6176612f6c616e672f4f626a656374 java/lang/Object
#23
tag:01
length:0010
bytes:6a6176612f6c616e672f53797374656d java/lang/System
#24
tag:01
length:0003
bytes:6f7574 out
#25
tag:01
length:0015
bytes:4c6a6176612f696f2f5072696e7453747265616d3b Ljava/io/PrintStream;
#26
tag:01
length:0013
bytes:6a6176612f696f2f5072696e7453747265616d java/io/PrintStream
#27
tag:01
length:0007
bytes:7072696e746c6e println
#28
tag:01
length:0015
bytes:284c6a6176612f6c616e672f537472696e673b2956 (Ljava/lang/String;)V

以上就是所有常量池的常量項,我們可以通過命令直接看結果javap -verbose First
在這裏插入圖片描述
結果與我們分析的結果一樣。

今天就到這,以後繼續分析;

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