1、運行時常量池是什麼
運行時常量池(Runtime Constant Pool),它是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述等信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後存放到常量池中。
瞭解java內存管理看這裏:jvm是如何管理內存的
如圖:
運行時常量是相對於常量來說的,它具備一個重要特徵是:動態性。當然,值相同的動態常量與我們通常說的常量只是來源不同,但是都是儲存在池內同一塊內存區域。
Java語言並不要求常量一定只能在編譯期產生,運行期間也可能產生新的常量,這些常量被放在運行時常量池中。這裏所說的常量包括:基本類型包裝類(包裝類不管理浮點型,整形只會管理-128到127)和String(也可以通過String.intern()方法可以強制將String放入常量池)。
瞭解基本類型包裝器看這裏:什麼是基本類型包裝器
例子:
public class TestConst {
public static String CONST_A = "the const b";// 編譯時放入常量池
public String const_b;
public Integer const_b_i;
public Integer const_b_ii;
public Float const_b_f;
public static void main(String[] args) {
TestConst testConst = new TestConst();
testConst.const_b = "the const b";// 運行時放入常量池
testConst.const_b_i = 12;// 運行時放入常量池
testConst.const_b_ii = 128;// 超過127,所以不會放入常量池
testConst.const_b_f = 2.0f;// 浮點包裝器不放入常量池
String const_c = "the const b";// 運行時放入常量池
Integer const_c_i = 12;// 運行時放入常量池
Integer const_c_ii = 128;// 超過127,所以不會放入常量池
Float const_c_f = 2.0f;// 浮點包裝器不放入常量池
System.out.println(CONST_A == const_c);
System.out.println(CONST_A == testConst.const_b);
System.out.println(testConst.const_b == const_c);
System.out.println(testConst.const_b_i == const_c_i);
System.out.println(testConst.const_b_ii == const_c_ii);
System.out.println(testConst.const_b_f == const_c_f);
}
}
運行結果:
true
true
true
true
false
false
Java虛擬機對Class文件的每一部分的格式都有嚴格的規定,每一個字節用於存儲哪種數據都必須符合規範,這樣纔會被虛擬機裝載和執行。但對於運行時常量池,Java虛擬機規範沒有做任何細節的要求,不同的提供商實現的虛擬機可以按照自己的需要來實現這個內存區域。
由於運行時常量池是方法區的一部分,所以會受到方法區內存的限制,當常量池無法再申請到內存時會拋出OutOfMemoryError: PermGen space異常。
在Java 8以後移除了方法區,由本地元空間代替,運行時常量池也放在了本地元空間中,如果這個區內存溢出,則會拋出OutOfMemoryError: Metaspace錯誤。