天天看點

基于JDK1.8 分析運作時常量池、字元串常量池、各種常量池

Java中的常量池分為三種類型:

    類檔案中常量池(The Constant Pool)

    運作時常量池(The Run-Time Constant Pool)

    String常量池

類檔案中常量池 ---- 存在于Class檔案中

所處區域:堆

誕生時間:編譯時

内容概要:符号引用和字面量

class常量池是在編譯的時候每個class都有的,在編譯階段,存放的是常量的符号引用。

常量池中存放的是符号資訊,java虛拟機在執行指令的時候會依賴這些資訊。常量池中的所有項都具有如下通用格式:

    cp_info {

     u1 tag;     //表示cp_info的單位元組标記位

     u1 info[];  //兩個或更多的位元組表示這個常量的資訊,資訊格式由tag的值确定

    }

Constant Type     Value

CONSTANT_Class     7

CONSTANT_Fieldref     9

CONSTANT_Methodref     10

CONSTANT_InterfaceMethodref     11

CONSTANT_String     8

CONSTANT_Integer     3

CONSTANT_Float     4

CONSTANT_Long     5

CONSTANT_Double     6

CONSTANT_NameAndType     12

CONSTANT_Utf8     1

CONSTANT_MethodHandle     15

CONSTANT_MethodType     16

CONSTANT_InvokeDynamic     18

舉幾個典型的例子來說明常量池中資料是如何存儲的:

CONSTANT_Class結構 -- 表示類或者接口,他的格式如下:

    CONSTANT_Class_info {

     u1 tag;       //這個值為 CONSTANT_Class (7)

     u2 name_index;//注意這是一個index,他表示一個索引,引用的是CONSTANT_UTF8_info

    }

注意觀察 這個CONSTANT_Class_info類型的常量内部結構是由一個tag(CONSTANT_Class(7))和一個name_index組成,name_index中注意這個index,他表示一個索引的,什麼的索引呢?CONSTANT_Utf8_info結構的索引,這個結構用來表示一個有效的類或者接口的二進制名稱的内部形式。class檔案結構中出現的類或者接口名稱都是通過全限定形式來表示的,也被稱作二進制名稱【題外話:全限定類名含義就類似 java.lang包中定義的Object類的完全限定名稱為java.lang.Object】。

那我們接着看CONSTANT_Utf8_info結構,他用于表示字元常量的值,他的結構如下所示:

    CONSTANT_Utf8_info {

     u1 tag;

     u2 length;

     u1 bytes[length];

    }

我們注意到第一個tag肯定表示為:CONSTANT_Utf8(1);後面的length指明了bytes[]數組的長度;最後一個bytes[]數組引用了上一個length作為其長度。字元常量采用改進過的UTF-8編碼表示。

運作時常量池 ---- 存在于記憶體的元空間中

誕生時間:JVM運作時

内容概要:class檔案元資訊描述,編譯後的代碼資料,引用類型資料,類檔案常量池。

所謂的運作時常量池其實就是将編譯後的類資訊放入運作時的一個區域中,用來動态擷取類資訊。

運作時常量池是在類加載完成之後,将每個class常量池中的符号引用值轉存到運作時常量池中,也就是說,每個class都有一個運作時常量池,類在解析之後,将符号引用替換成直接引用,與全局常量池中的引用值保持一緻。

字元串常量池 ---- 存在于堆中

從上述結果可以看出,JDK 1.6下,會出現“PermGen Space”的記憶體溢出,而在 JDK 1.7和 JDK 1.8 中,會出現堆記憶體溢出,并且 JDK 1.8中 PermSize 和 MaxPermGen 已經無效。是以,可以大緻驗證 JDK 1.7 和 1.8 将字元串常量由永久代轉移到堆中,并且 JDK 1.8 中已經不存在永久代的結論。

字元串池裡的内容是在類加載完成,經過驗證,準備階段之後在堆中生成字元串對象執行個體,然後将該字元串對象執行個體的引用值存到string pool中(記住:string pool中存的是引用值而不是具體的執行個體對象,具體的執行個體對象是在堆中開辟的一塊空間存放的)。 在HotSpot VM裡實作的string pool功能的是一個StringTable類,它是一個哈希表,裡面存的是駐留字元串(也就是我們常說的用雙引号括起來的)的引用(而不是駐留字元串執行個體本身),也就是說在堆中的某些字元串執行個體被這個StringTable引用之後就等同被賦予了”駐留字元串”的身份。這個StringTable在每個HotSpot VM的執行個體隻有一份,被所有的類共享。

https://www.cnblogs.com/dennyzhangdd/p/6770188.html

————————————————

版權聲明:本文為CSDN部落客「LJHSkyWalker」的原創文章,遵循 CC 4.0 BY-SA 版權協定,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/qq_31615049/article/details/81611918