JVM中的常量池詳解

在Java的內存分配中,總共3種常量池:javascript

轉發連接:https://blog.csdn.net/zm13007310400/article/details/77534349java

1.字符串常量池(String Constant Pool):

1.1:字符串常量池在Java內存區域的哪一個位置?

  • 在JDK6.0及以前版本,字符串常量池是放在Perm Gen區(也就是方法區)中;
  • 在JDK7.0版本,字符串常量池被移到了堆中了。至於爲何移到堆內,大概是因爲方法區的內存空間過小了。
  • JDK8之後也仍是放在了Heap空間中,並無已到元空間。

1.2:字符串常量池是什麼?

  • 在HotSpot VM裏實現的string pool功能的是一個StringTable類,它是一個Hash表,默認值大小長度是1009;這個StringTable在每一個HotSpot VM的實例只有一份,被全部的類共享。字符串常量由一個一個字符組成,放在了StringTable上。
  • 在JDK6.0中,StringTable的長度是固定的,長度就是1009,所以若是放入String Pool中的String很是多,就會形成hash衝突,致使鏈表過長,當調用String#intern()時會須要到鏈表上一個一個找,從而致使性能大幅度降低;
  • 在JDK7.0中,StringTable的長度能夠經過參數指定:
-XX:StringTableSize=66666
  • 1

1.3:字符串常量池裏放的是什麼?

  • 在JDK6.0及以前版本中,String Pool裏放的都是字符串常量;
  • 在JDK7.0中,因爲String#intern()發生了改變,所以String Pool中也能夠存放放於堆內的字符串對象的引用。關於String在內存中的存儲和String#intern()方法的說明,能夠參考個人另一篇博客:

須要說明的是:字符串常量池中的字符串只存在一份! 
如:ruby

String s1 = "hello,world!"; String s2 = "hello,world!";
  • 1
  • 2

即執行完第一行代碼後,常量池中已存在 「hello,world!」,那麼 s2不會在常量池中申請新的空間,而是直接把已存在的字符串內存地址返回給s2。(這裏具體的字符串如何分配就不細說了,能夠看個人另外一篇博客)jvm

2.class常量池(Class Constant Pool):

2.1:class常量池簡介:

  • 咱們寫的每個Java類被編譯後,就會造成一份class文件;class文件中除了包含類的版本、字段、方法、接口等描述信息外,還有一項信息就是常量池(constant pool table),用於存放編譯器生成的各類字面量(Literal)和符號引用(Symbolic References);
  • 每一個class文件都有一個class常量池。

2.2:什麼是字面量和符號引用:

  • 字面量包括:1.文本字符串 2.八種基本類型的值 3.被聲明爲final的常量等;
  • 符號引用包括:1.類和方法的全限定名 2.字段的名稱和描述符 3.方法的名稱和描述符。

3.運行時常量池(Runtime Constant Pool):

  • 運行時常量池存在於內存中,也就是class常量池被加載到內存以後的版本,不一樣之處是:它的字面量能夠動態的添加(String#intern()),符號引用能夠被解析爲直接引用
  • JVM在執行某個類的時候,必須通過加載、鏈接、初始化,而鏈接又包括驗證、準備、解析三個階段。而當類加載到內存中後,jvm就會將class常量池中的內容存放到運行時常量池中,由此可知,運行時常量池也是每一個類都有一個。在解析階段,會把符號引用替換爲直接引用,解析的過程會去查詢字符串常量池,也就是咱們上面所說的StringTable,以保證運行時常量池所引用的字符串與字符串常量池中是一致的。
public static void main(String[] args) {
        String s1="abc";
        String s2="abc";
        System.out.println(s1==s2);//true
        String s3=new String("ab")+new String("c");
        
        // 這裏顯示false,可能先在字符串常量池中添加s1,而後動態的添加s3,會顯示false
        s3.intern();     
        System.out.println(s1==s3); //false
         
        String s4=new String("ab")+new String("cd");
        //s4.intern();
        String s5="abcd";
        System.out.println(s4==s5);//true,去掉intern以後是false;
         
    }    
相關文章
相關標籤/搜索