【JVM虛擬機】(5)---深刻理解JVM-Class中常量池

<center>深刻理解Class---常量池</center>

<font color=#FFD700> 1、概念</font>

一、jvm生命週期

啓動:當啓動一個java程序時,一個jvm實例就誕生了,任何一個擁有main方法的class均可以做爲jvm實例運行的起點。java

運行:main()函數做爲程序初始線程起點,其它線程由該線程啓動,包括守護線程(daemon)和non-daemon(普通線程)。守護線程是JVM本身使用的線程好比GC線程就是個守護線程,只要這個jvm實例還有普通線程執行,就不會中止,可是能夠用exit()強制終止程序。安全

消亡:全部非守護線程退出時,JVM實例結束生命,若安全管理器容許,程序也可使用java.lang.Runtime類或者System.exit(0)來退出。實際上exit也是用到Runtime類來退出,Runtime是個神奇的類,它還能夠用於啓動和關閉非java進程。網絡

二、JVM與Class文件

咱們一直說java虛擬機實現的與語言是無關的,java虛擬機不和包含java在內的任何語言綁定,它只和與class文件這種特殊的二進制文件格式所關聯,class文件中包含了java虛擬機指令集符號表以及若干其餘輔助信息。基於安全方面的考慮, Java 慮擬機規範要求在 Class 文件中使用許多強制性的語法和結構化約束,但任一門功能性語言均可以表示爲一個能被 Java 虛擬機所接受的有效的 Class 文件。做爲一個通用的、機器無關的執行平臺,任何其餘語言的實現者均可以將 Java 虛擬機做爲語言的產品交付媒介。例如,使用 Java 編譯器能夠把 Java 代碼編譯爲存儲字節碼的 Class 文件,使用 JRuby 等其餘語言的編譯器一樣能夠把程序代碼編譯成 Class 文件,虛擬機並不關心Class 的來源是何種語言,如圖。dom

三、什麼是Class文件

Java字節碼類文件(.class)是Java編譯器編譯Java源文件(.java)產生的「目標文件」。它是一種8位字節的二進制流文件, 各個數據項按順序緊密的從前向後排列, 相鄰的項之間沒有間隙, 這樣可使得class文件很是緊湊, 體積輕巧, 能夠被JVM快速的加載至內存, 而且佔據較少的內存空間(方便於網絡的傳輸)。jvm

class文件是一組以8位字節爲基礎單位的二進制流。

class文件中的信息是一項一項排列的, 每項數據都有它的固定長度, 有的佔一個字節, 有的佔兩個字節, 還有的佔四個字節或8個字節, 數據項的不一樣長度分別用u1, u2, u4, u8表示, 分別表示一種數據項在class文件中佔據一個字節, 兩個字節, 4個字節和8個字節。編輯器

四、什麼是魔數

當咱們把class文件轉成16進制,咱們能夠看到文件的頭四個字節是cafe babe,這個就稱爲魔數。,它惟一做用就告訴虛擬機當前的文件就是class文件。 使用魔數而不是用擴展名來進行識別主要是基於安全考慮,由於擴展名咱們能夠隨意經過重命名等方式改動。而經過魔數就算你把結尾改爲.clss。但它一樣還能在JVM運行,由於它的頭部仍是cafe babe沒變。 不少文件存儲標準中都用魔數進行身份標識,如圖片gif,jpeg都在文件頭部中存儲着魔數。函數

五、jvm常量池

我先講下概念,接下來我會將class文件轉爲16進制流後,在舉例說明。工具

常量池中每一項常量都是一個表,jdk1.8有14種結構不一樣的表結構,這14個表有個共同特色,就是表開始的第一位都是一個u1類型的標誌位,JVM根據這個標誌位[tag]來肯定某個常量池項表示什麼類型的字面量,好比tag爲1就是指CONSTANT_utf8_info編碼

再看常量池類型表spa

這14種常量項結構還有一個特色是,其中13表佔用得字節固定,只有CONSTANT_Utf8_info佔用字節不固定,其大小由length決定。爲何呢?由於從常量池存放的內容可知,其存放的是字面量和符號引用,最終這些內容都會是一個字符串, 這些字符串的大小是在編寫程序時才肯定,好比你定義一個類,類名能夠取長取短,因此在沒編譯前,沒法肯定大小不固定,編譯後,經過utf-8編碼,就能夠知道其長度。

在看每一項常量表對應的說明:

<br>

<font color=#FFD700> 2、16進制class文件解析</font>

先看java代碼

package com.jincou.demo.domain;
public class XiaoXiao {
    private String father;
    public String fatherName() {
        return "小小她爹";
    }
}

經過命令自動生成class文件(會在同一目錄生成)

javac XiaoXiao.java

在將class文件拖入文本編輯器裏,顯示天然就是16進制流了,以下:

<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190402230800719-150205933.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="500">

上面的表其實能夠劃分爲如下七個部分,.class 字節碼文件包括:

  • 魔數與class文件版本
  • 常量池
  • 訪問標誌
  • 類索引、父類索引、接口索引
  • 字段表集合
  • 方法表集合
  • 屬性表集合

這篇博客只講到常量池,其它的下篇講,接下來咱們一行一行解釋,首先是:

cafe babe:上面說過了這個是魔數,告訴JVM虛擬機我就是class文件。

0000 0034:次版本號組成u2+主版本號u2。共佔4個字節。0034轉10進製爲52,表明當前JDK版本爲1.8。

0013 :說明有19-1即18個常量。

上面這些位置是固定的。接下來就是說明每個常量:

0a:這就是tag表明一個標誌,0a表明10,去找常量池列表。

得知它是一個接口中方法的符號引用,而後去找CONSTANT_Methodref_info對應常量列表描述:

從常量列表咱們能夠知道該類型一共佔了5u,即0a00 0400 0f,那麼下一個tag就是08表明字符串類型常量,以此類推就能夠知道一共18個常量的信息。 <br>

<font color=#FFD700> 3、class反編譯</font>

經過上面看16進制的卻太麻煩了,如今咱們能夠經過JDK自帶反編譯工具查看會更加清晰。

javap -verbose 文件名

經過反編譯看去就很直觀,好比第一個字符常量很明顯告訴你是CONSTANT_Methodref_info,並且對於的就是4和15和上面完美對應。

最後思考,到底哪些會放到常量池?

1.常量池能夠理解爲class文件中的資源倉庫,有不少種類型,主要存放兩大常量
①.字面量 
字面量就是通俗理解的java常量,如文本字符串,8大基本數據類型,final修飾的常量值等
②.符號引用
符號引用屬於編譯原理的概念,主要包含如下三種
1)類和接口的全限定名
2)字段的名稱和描述符
3)方法的名稱和描述符

<br>

<font color=#FFD700> 參考</font>

一、深刻了解java虛擬機第2版第六章

二、深刻理解JVM-Class文件結構和類加載

三、深刻理解JVM之Java字節碼(.class)文件詳解

<br>

<br>

只要本身變優秀了,其餘的事情纔會跟着好起來(少將3)
相關文章
相關標籤/搜索