?JDK8以后,運行時常量池邏輯上屬于方法區;但:
- 其中的字符串常量池實際位置移至到了java堆;
- 其中一些符號引用也存儲到了元空間;
- 字符串常量池,元空間,運行時常量區的具體關系請看這篇博客:
JDK8+后,運行時常量池、字符串常量池和元空間的關-CSDN博客
????????JVM 方法區(Method Area) 中的 運行時常量池(Runtime Constant Pool) 存儲的數據來源于 類文件常量池(Class File Constant Pool),并在運行時進行動態解析和擴展。具體存儲的內容可以分為以下幾類:
1. 類文件常量池的原始數據(編譯期生成)
在 .class
文件中,常量池(Constant Pool)存儲了各種符號信息,JVM 在加載類時會將其解析到運行時常量池。主要包括:
(1) 字面量(Literals)
-
字符串常量(
String
):如"Hello"
(最終可能被放入字符串池String Table
)。 -
數值常量:
-
整型(
int
,long
,short
,byte
,char
):如123
,0x1F
。 -
浮點型(
float
,double
):如3.14
,2.71828
。
-
-
final
常量(無論是否static
):-
static final int MAX = 100;
(靜態常量) -
final String NAME = "Java";
(實例常量)
-
(2) 符號引用(Symbolic References)
-
類和接口的全限定名(Fully Qualified Name):如
java/lang/String
。 -
字段的名稱和描述符(Field Name & Descriptor):
-
如
Ljava/lang/String;
(字段類型描述符)。
-
-
方法的名稱和描述符(Method Name & Descriptor):
-
如
main([Ljava/lang/String;)V
(main
方法的描述符)。
-
-
方法句柄(MethodHandle)和動態調用點(InvokeDynamic)信息(Java 7+)。
2. 運行時動態解析的數據
在類加載、鏈接(驗證、準備、解析)階段,JVM 會將符號引用轉換為直接引用:
-
類/接口的解析:將
java/lang/Object
轉換為實際類對象的引用。 -
字段解析:將字段符號引用轉換為內存偏移量或
Field
對象。 -
方法解析:將方法符號引用轉換為方法入口地址(
Method
對象或 JNI 指針)。 -
動態計算的常量(Java 8+):
-
如
CONSTANT_Dynamic
(invokedynamic
指令使用的動態常量)。
-
3. 動態生成的常量
-
String.intern()
的字符串:-
調用
"abc".intern()
后,字符串會被放入字符串池(String Table),邏輯上屬于運行時常量池的一部分(但 HotSpot 的字符串池在堆中)。
-
-
動態代理類、Lambda 表達式生成的類信息(可能涉及新的常量池條目)。
-
Class
對象引用:如String.class
的運行時表示。
4. 其他 JVM 內部使用的數據
-
基本類型的包裝類緩存:
如Integer.valueOf(1)
會緩存-128~127
,這些值可能被復用。 -
特殊常量:
null
的表示,以及某些 JVM 內部使用的標記常量(如異常類名)。
總結:運行時常量池存儲哪些數據?
數據類型 | 示例 | 是否動態解析 |
---|---|---|
字符串常量 | "Hello" | 可能 intern() |
數值常量 | 123 , 3.14 | 否 |
final 常量 | static final int X=1 | 可能內聯優化 |
類和接口全限定名 | java/lang/String | 解析為 Class |
字段/方法符號引用 | Ljava/lang/String; | 解析為直接引用 |
動態計算的常量 | CONSTANT_Dynamic (Java 8+) | 運行時計算 |
String.intern() | "abc".intern() | 動態添加 |
關鍵點
-
運行時常量池不僅存儲靜態常量,還包括所有類文件的常量池信息 + 運行時解析的數據。
-
符號引用會在類加載時解析,變成直接引用(如內存地址、方法指針等)。
-
字符串常量可能被
intern()
并放入字符串池(HotSpot 中字符串池在堆,但邏輯屬于運行時常量池)。 -
動態語言支持(如
invokedynamic
) 會新增動態計算的常量。
如果你對某部分內容(如字符串池、符號引用解析)想深入了解,可以進一步討論!
?常見誤區澄清
-
誤區:“運行時常量池只存靜態常量”。 事實:它存儲所有類文件常量池的內容,包括動態解析的引用和字面量。
-
字符串池的特殊性: 在HotSpot JVM中,字符串池(String Table)實際位于堆內存,而非方法區,但邏輯上屬于運行時常量池的一部分。
靜態 vs. 非靜態常量
-
靜態常量(
static final
): 例如public static final int MAX = 100;
,這類常量會被存入運行時常量池,但它們的值可能進一步被內聯到使用它們的代碼中(編譯期優化)。 -
非靜態常量(實例級
final
常量): 例如private final String name = "Hello";
,雖然字面量"Hello"
會存儲在運行時常量池中,但該常量值是與對象實例綁定的,需要通過實例訪問。