Constant Pool

常量池的優勢

為了避免頻繁的創建和銷毀對象而影響系統性能,其實現了對象的共享。

解析流程

與 ClassLoader 機制息息相關

ClassLoader 機制
  1. ClossLoading 編譯時期 (Class Constant Pool)

  2. ClossLoading 加載完成 (將 Class Constant Pool 的內容存放到 Runtime Constant Pool 中)

  3. Linking / 準備 (String literal Pool 生成參考值)

  4. Linking / 解析 (運行時常量池中的符號參考替換成直接參考)

Class Constant Pool

每個類別 ClossLoading 時期產生,.class 文件中除了包含類別的版本、屬性、方法、介面等描述信息放在方法區外,另外就是常量池 (constant pool table),用於存放生成的兩大類型常量:

字面量 (Literal)

  • 字串

  • 被聲明為 final 的常量參數值

符號參考 (Symbolic References)

  • 類別和介面的全名 - 如:Object,Ljava/lang/Object;

  • 屬性的名稱和權限符號

  • 方法的名稱和權限符號

名稱參考 .class 結構

N .class 結構

Runtime Constant Pool

ClassLoader 加載完成後,就會將 .class常量池中的內容存放到運行時常量池中,

由此可知,運行時常量池內也是每個類別都會有一份內容

Runtime Constant Pool 相對於 Class Constant Pool 的另一個重要特徵是具備動態性。

運行時常量池裡的內容是能夠動態添加的。

String literal Pool

又稱 String pool,是在 .class classLoading 完成,並經過驗證,到了"準備" 階段之後,

在 Heap 中生成字串的對象,然後將該字串對象的參考值存到 string pool 中,

具體的實例對象是存放在 Heap 中的一塊空間,屬於 Global Pool。

HotSpot VM 中實作的方式

是透過一個 StringTable 類別,是一個 hashTable,存的是 駐留字符串 (也就是用雙引號括起來的字)的參考(而不是駐留字符串對象本身)。

也就是說在 Heap 中的某些字串對象被這個 StringTable 參考之後就等同被賦予了 "駐留字符串" 的身份。

在解析階段時,會把運行時常量池中的符號參考替換成直接參考,就會直接查詢StringTable,保證 StringTable 裡的參考值與運行時常量池中的參考值一致。

這個 StringTable 在每個 HotSpot VM 中只有一份,即共享池的概念。

優點

  • 節省內存空間

    • 常量池中所有相同的字符串常量被合併,只佔用一個空間。

  • 節省運行時間

    • 比較字符串時,== 比 equals() 快。 對於兩個引用變量,只用 == 判斷是否相等,也就可以判斷實際值是否相等。

比較(equal)

String 類別的 intern() 方法

是一個 Native 方法。

會查找 String pool 中是否存在一份 equal 相等的字符串,如果有則返回該字符串的參考,

如果沒有則添加新的字符串進入池中。

參考資料

http://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/ https://www.jianshu.com/p/c7f47de2ee80 https://blog.csdn.net/qq_26222859/article/details/73135660

Last updated

Was this helpful?