JVM擴(kuò)展(3):常量池引發(fā)的一連串思考(下)

   百度百科:
  https://baike.baidu.com/item/%E5%B8%B8%E9%87%8F%E6%B1%A0/3855836?fr=aladdin

 先暫時(shí)認(rèn)為:JDK1.8 的所有類型常量池都存儲(chǔ)在元空間(方法區(qū)) (后續(xù)會(huì)有解釋)
目錄
  1:源碼的編譯(包括類加載過(guò)程)
  2:靜態(tài)常量池(類常量池)(類文件常量池)(class constant pool)  (編譯期)  
  3:全局常量池(String pool)(類加載過(guò)程中)
  4:運(yùn)行時(shí)常量池(runtime constant pool)(類加載完成后)
  5:string的實(shí)例對(duì)象 講解
  6:常量池的邏輯存儲(chǔ)與物理存儲(chǔ)
  7:常量池存儲(chǔ)位置的 結(jié)論      
  8:靜態(tài)常量池 全局常量池  運(yùn)行時(shí)常量池  的關(guān)系
1:源碼的編譯(包括類加載過(guò)程)
1:Java源代碼 
2:經(jīng)過(guò)JDK中Javac 編譯
3:字節(jié)碼文件(.class)
4:JVM 類加載器     進(jìn)行加載字節(jié)碼文件

5:方法:解釋:
     1:解釋器      逐行解釋執(zhí)行
     2:機(jī)器可執(zhí)行的二進(jìn)制機(jī)器碼

5:方法:編譯:
     后續(xù)引進(jìn):JIT即時(shí)編譯器(Just In Time Compiler)
     處理熱點(diǎn)代碼(一次編譯 多次執(zhí)行)
     2:JIT      運(yùn)行時(shí)進(jìn)行編譯
     3:機(jī)器可執(zhí)行的二進(jìn)制機(jī)器碼
     4:編譯完成后機(jī)器碼保留
     5:機(jī)器碼下次可以直接使用

類加載過(guò)程:
     其中l(wèi)oadClass的類加載過(guò)程有如下幾步:
    加載 >> 驗(yàn)證 >> 準(zhǔn)備 >> 解析 >> 初始化
2:靜態(tài)常量池(類常量池)(類文件常量池)(class constant pool) (編譯期)
java文件被編譯成class文件之后,就是會(huì)生成類文件,也就是會(huì)生成里面的類常量池。

類文件包含兩大部分
    1:類型信息:類的版本、字段、方法、接口等描述信息外
    2:靜態(tài)常量池(class constant pool ),
        1:各種字面量(Literal)
        2:符號(hào)引用(Symbolic References)。
    
字面量:常量等
符號(hào)引用:與直接引用(指針)區(qū)分 ,同樣的也可以無(wú)歧義的定位到對(duì)應(yīng)目標(biāo)。
3:全局常量池(String pool)(類加載過(guò)程中)
全局字符串池里的內(nèi)容是在類加載過(guò)程中,經(jīng)過(guò)驗(yàn)證,準(zhǔn)備階段之后在堆中生成字符串對(duì)象實(shí)例,
然后將該字符串對(duì)象實(shí)例的引用值存到string pool中。(存放的是地址 而 不是對(duì)象本身)

HotSpot VM里實(shí)現(xiàn)的string pool功能的是一個(gè)StringTable類,
它是一個(gè)哈希表這個(gè)StringTable在每個(gè)HotSpot VM的實(shí)例只有一份,被所有的類共享。
4:運(yùn)行時(shí)常量池(runtime constant pool)(類加載完成后)
JVM在執(zhí)行某個(gè)類的時(shí)候,必須經(jīng)過(guò)首次類加載。
而當(dāng)首次類加載把類到內(nèi)存中后,jvm就會(huì)將   類常量池中的內(nèi)容    存放到運(yùn)行時(shí)常量池中,由此可知,運(yùn)行時(shí)常量池也是每個(gè)類都有一個(gè)。

由于靜態(tài)常量池中存的是對(duì)象的符號(hào)引用。

1:類加載過(guò)程中的解析過(guò)程 :使用類常量池中的符號(hào)引用   查詢  全局常量池
2:把符號(hào)引用 替換成  直接引用(指針)
3:把類常量池的內(nèi)存  全部存放到   運(yùn)算時(shí)常量池
4:保證運(yùn)行時(shí)常量池所引用的字符串與全局字符串池中所引用的是一致的。
5:string的實(shí)例對(duì)象 講解

public class HelloWorld {
    public static void main(String []args) {
        String str1 = "hesuijin";
        String str2 = "hesuijin";
        
        String str3 = new String("HSJ");
        String str4 = str3.intern();
        String str5 = "HSJ";
        
        System.out.println(str1 == str2);//true
        System.out.println(str3 == str4);//false
        System.out.println(str4 == str5);//true
    }
}
引用值 = 引用地址 = 地址  =  指針

1:執(zhí)行第一句:堆中會(huì)有一個(gè)”hesuijin”實(shí)例,全局常量池    中存放著”hesuijin”的一個(gè)引用值

2:執(zhí)行第二句: 解析str3的時(shí)候查找全局常量池,里面有”hesuijin”的引用值,
                    所以str3的引用值與之前的那個(gè)已存在的相同;

3:執(zhí)行第三句:時(shí)候會(huì)生成兩個(gè)實(shí)例(兩者不一樣):
        1:堆中會(huì)有一個(gè)”HSJ”實(shí)例,全局常量池中存放著”HSJ”的一個(gè)引用值
        2:一個(gè)是New出來(lái)的一個(gè)”HSJ”的實(shí)例對(duì)象 (正常對(duì)象)
    最后str3會(huì)使用默認(rèn)New出來(lái)的實(shí)例對(duì)象的引用值
            
4:執(zhí)行第四句:intern()函數(shù)   如果存在 全局常量池中 str3 的引用值 則返回 ,
                                     如果沒有就將New出來(lái)的實(shí)例對(duì)象的引用值添加進(jìn)去;
                                     現(xiàn)在存在 因此返回 全局常量池中”HSJ”的引用值
                                     
5:執(zhí)行第五句:解析str5的時(shí)候查找全局常量池,里面有”HSJ”的引用值,
                    所以str5的引用值與之前的那個(gè)已存在的相同;

因此:str1(全局常量池中)     str2 (全局常量池中)     一致   
     str3(New出來(lái)的對(duì)象)    str4 (全局常量池中)     不一致
     str4(全局常量池中)     str5 (全局常量池中)     一致
6:常量池的邏輯存儲(chǔ)與物理存儲(chǔ)
  取消永久代后,使用元空間來(lái)實(shí)現(xiàn)方法區(qū)。        
  在JDK1.8中,把JDK 7中永久代還剩余的內(nèi)容(主要是類型信息)全部移到元空間中。
 
  注意這里的剩余內(nèi)容:說(shuō)明原來(lái)移除從永久代移出的字符串常量池,靜態(tài)常量池,運(yùn)行時(shí)常量池 ,
                            在更換了方法區(qū)實(shí)現(xiàn)后,并沒有順勢(shì)進(jìn)入到元空間,那么它們到哪里去了呢?

  在JDK1.8中,使用元空間代替永久代來(lái)實(shí)現(xiàn)方法區(qū),但是方法區(qū)并沒有改變,
  所謂"Your father will always be your father",變動(dòng)的只是方法區(qū)中內(nèi)容的物理存放位置。
    
  正如上面所說(shuō),類型信息(元數(shù)據(jù)信息)等其他信息被移動(dòng)到了元空間中;

  但是常量池(靜態(tài)常量池  運(yùn)行時(shí)常量池)和字符串常量池被移動(dòng)到了堆中。
  
  但是不論它們物理上如何存放,邏輯上還是屬于方法區(qū)(元空間)。
  但是不論它們物理上如何存放,邏輯上還是屬于方法區(qū)(元空間)。
  但是不論它們物理上如何存放,邏輯上還是屬于方法區(qū)(元空間)。
7:常量池存儲(chǔ)位置的 結(jié)論
 那么現(xiàn)在我們可以看到有三種常量池:
 
 靜態(tài)常量池(類常量池)(類文件常量池)(class constant pool) 
 運(yùn)行時(shí)常量池(runtime constant pool) 
 字符串常量池(全局常量池)(String pool)
 
 考慮其物理存儲(chǔ)位置 應(yīng)該是存放在堆中
 但考慮其邏輯存儲(chǔ)位置  應(yīng)該是存放在元空間(方法區(qū))中

那么在絕大多數(shù)的網(wǎng)上說(shuō)法 都是指

堆存放的是 對(duì)象 數(shù)組引用類型 非靜態(tài)變量    String(物理存儲(chǔ))
方法區(qū): 靜態(tài)變量、常量, 靜態(tài)和非靜態(tài)的方法  類信息  String(邏輯存儲(chǔ))

那么現(xiàn)在我們先以邏輯存儲(chǔ)位置為準(zhǔn): 
JDK1.8 的所有類型常量池都存儲(chǔ)在元空間(方法區(qū))

那么現(xiàn)在我們先以邏輯存儲(chǔ)位置為準(zhǔn): 
JDK1.8 的所有類型常量池都存儲(chǔ)在元空間(方法區(qū))

那么現(xiàn)在我們先以邏輯存儲(chǔ)位置為準(zhǔn): 
JDK1.8 的所有類型常量池都存儲(chǔ)在元空間(方法區(qū))
8:靜態(tài)常量池 全局常量池 運(yùn)行時(shí)常量池 的關(guān)系
所有的常量池都存儲(chǔ)在元空間(方法區(qū))

1:編譯期:靜態(tài)常量池(類常量池)(類文件常量池)(class constant pool)
2:類加載期:全局常量池(String pool)
3:類加載完成期:運(yùn)行時(shí)常量池(runtime constant pool)

1:編譯期 產(chǎn)生靜態(tài)常量池 存放
    1:各種字面量(Literal)
    2:符號(hào)引用(Symbolic References)。

2:在類加載期 如果產(chǎn)生 字符串對(duì)象實(shí)例  
     1:String str1 = “hesuijin” 產(chǎn)生一個(gè)實(shí)例  
        那么會(huì)將str1實(shí)例對(duì)象地址存放到全局常量池
     
     2:String str2 = new String(“HSJ”) 產(chǎn)生兩個(gè)實(shí)例         
         1:那么會(huì)將str2 其中一個(gè)實(shí)例對(duì)象地址存放到全局常量池
         2:那么會(huì)將 new 出來(lái)的一個(gè)實(shí)例對(duì)象 當(dāng)成正常對(duì)象處理
             其str2 地址指向 new出來(lái) 的一個(gè)實(shí)例對(duì)象

3:類加載完成后 
         1:靜態(tài)常量池的 各種字面量(Literal) 會(huì)復(fù)制一份到 運(yùn)行時(shí)常量池
         2:靜態(tài)常量池的 符號(hào)引用(Symbolic References) 經(jīng)過(guò) 全局常量池轉(zhuǎn)換后  會(huì)復(fù)制一份到 運(yùn)行時(shí)常量池
         3:通過(guò)其他途徑創(chuàng)建的常量 :如基本類型的包裝類  如String 也會(huì)加入到 運(yùn)行時(shí)常量池
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ??需要說(shuō)明的一點(diǎn)是,這篇文章是以《深入理解Java虛擬機(jī)》第二版這本書為基礎(chǔ)的,這里假設(shè)大家已經(jīng)了解了JVM的運(yùn)...
    Geeks_Liu閱讀 14,280評(píng)論 5 44
  • JVM8-一道字符串題題帶你認(rèn)識(shí)常量池 請(qǐng)先做題并把答案記在心里 答案在文章最后面 常量池 常量池的數(shù)據(jù)存儲(chǔ)在方法...
    IT三明治閱讀 323評(píng)論 0 1
  • 這篇文章主要是做一個(gè)總結(jié),將查找到相關(guān)的資料自己做一個(gè)整理,最后會(huì)列出查找過(guò)的相關(guān)資料,感興趣的可以去翻一翻。 常...
    BigX閱讀 1,129評(píng)論 0 6
  • 目錄 1:什么叫常量池 2:常量結(jié)構(gòu)實(shí)例說(shuō)明 3:字符串常量特殊講解 4:拘留字的實(shí)際使用 與 常量池的作用 5...
    _River_閱讀 272評(píng)論 0 1
  • 1.常量池類型 Java中的常量池分為三種: 類文件常量池(靜態(tài)常量池)(The Constant Pool)運(yùn)行...
    hadoop_a9bb閱讀 1,116評(píng)論 0 0

友情鏈接更多精彩內(nèi)容