Class常量池可以理解為是Class檔案中的資源倉庫, Class檔案中除了包含類的版本、欄位、方法、介面等描述資訊外, 還有一項資訊就是常量池(constant pool table),用于存放編譯器生成的各種字面量(Literal)和符號參考(Symbolic References),
一個class檔案的16進制大體結構如下圖:

對應的含義如下,細節可以查下oracle官方檔案

當然我們一般不會去人工決議這種16進制的位元組碼檔案,我們一般可以通過javap命令生成更可讀的JVM位元組碼指令文 件:
javap -v Math.class
Classfile /E:/open/demo/target/classes/com/example/demo/test/opencv/Math.class
Last modified 2020-9-20; size 619 bytes
MD5 checksum f70c67abc97af9f0978a807380fcb072
Compiled from "Math.java"
public class com.example.demo.test.opencv.Math
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #5.#26 // java/lang/Object."<init>":()V
#2 = Class #27 // com/example/demo/test/opencv/Math
#3 = Methodref #2.#26 // com/example/demo/test/opencv/Math."<init>":()V
#4 = Methodref #2.#28 // com/example/demo/test/opencv/Math.compute:()I
#5 = Class #29 // java/lang/Object
#6 = Utf8 <init>
#7 = Utf8 ()V
#8 = Utf8 Code
#9 = Utf8 LineNumberTable
#10 = Utf8 LocalVariableTable
#11 = Utf8 this
#12 = Utf8 Lcom/example/demo/test/opencv/Math;
#13 = Utf8 compute
#14 = Utf8 ()I
#15 = Utf8 a
#16 = Utf8 I
#17 = Utf8 b
#18 = Utf8 c
#19 = Utf8 main
#20 = Utf8 ([Ljava/lang/String;)V
#21 = Utf8 args
#22 = Utf8 [Ljava/lang/String;
#23 = Utf8 math
#24 = Utf8 SourceFile
#25 = Utf8 Math.java
#26 = NameAndType #6:#7 // "<init>":()V
#27 = Utf8 com/example/demo/test/opencv/Math
#28 = NameAndType #13:#14 // compute:()I
#29 = Utf8 java/lang/Object
{
public com.example.demo.test.opencv.Math();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/example/demo/test/opencv/Math;
public int compute();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=4, args_size=1
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: bipush 10
9: imul
10: istore_3
11: iload_3
12: ireturn
LineNumberTable:
line 6: 0
line 7: 2
line 8: 4
line 9: 11
LocalVariableTable:
Start Length Slot Name Signature
0 13 0 this Lcom/example/demo/test/opencv/Math;
2 11 1 a I
4 9 2 b I
11 2 3 c I
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: new #2 // class com/example/demo/test/opencv/Math
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method compute:()I
12: istore_2
13: return
LineNumberTable:
line 14: 0
line 15: 8
line 16: 13
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 args [Ljava/lang/String;
8 6 1 math Lcom/example/demo/test/opencv/Math;
13 1 2 compute I
}
SourceFile: "Math.java"
常量池中主要存放兩大類常量:字面量和符號參考,
字面量
字面量就是指由字母、數字等構成的字串或者數值常量
字面量只可以右值出現,所謂右值是指等號右邊的值,如:int a=1 這里的a為左值1為右值,在這個例子中1就是字面量,
int a = 1;
int b = 2;
int c = "abcdefg";
符號參考
符號參考是編譯原理中的概念,是相對于直接參考來說的,主要包括了以下三類常量:
- 類和介面的全限定名
- 欄位的名稱和描述符
- 方法的名稱和描述符
上面的a,b就是欄位名稱,就是一種符號參考,還有Math類常量池里的 Lcom/example/demo/test/opencv/Math 是類的全限定名, main和compute是方法名稱,()是一種UTF8格式的描述符,這些都是符號參考,
這些常量池現在是靜態資訊,只有到運行時被加載到記憶體后,這些符號才有對應的記憶體地址資訊,這些常量池一旦被裝 入記憶體就變成運行時常量池了,對應的符號參考在程式加載或運行時會被轉變為被加載到記憶體區域的代碼的直接參考, 也就是我們說的動態鏈接了,例如,compute()這個符號參考在運行時就會被轉變為compute()方法具體代碼在記憶體中 的地址,主要通過物件頭里的型別指標去轉換直接參考,
Jdk1.6及之前: 有永久代, 常量池在方法區
Jdk1.7:有永久代,但已經逐步“去永久代”,常量池在堆
Jdk1.8及之后: 無永久代,常量池在元空間
字串常量池
字串常量池的設計思想
- 字串的分配,和其他的物件分配一樣,耗費高昂的時間與空間代價,作為最基礎的資料型別,大量頻繁的創建 字串,極大程度地影響程式的性能
- JVM為了提高性能和減少記憶體開銷,在實體化字串常量的時候進行了一些優化
為字串開辟一個字串常量池,類似于快取區
創建字串常量時,首先堅持字串常量池是否存在該字串
存在該字串,回傳參考實體,不存在,實體化該字串并放入池中
代碼示例,一些字串區域變數操作
String str1 = "abc";
String str2 = "abc";
String str3 = "abc";
String str4 = new String("abc");
String str5 = new String("abc");
String str5 = new String("abc");

安全點與安全區域
安全點
安全點就是指代碼中一些特定的位置,當執行緒運行到這些位置時它的狀態是確定的,這樣JVM就可以安全的進行一些操作,比 如GC等,所以GC不是想什么時候做就立即觸發的,是需要等待所有執行緒運行到安全點后才能觸發, 這些特定的安全點位置主要有以下幾種:
- 方法回傳之前
- 呼叫某個方法之后
- 拋出例外的位置
- 回圈的末尾
安全區域
Safe Point 是對正在執行的執行緒設定的,
如果一個執行緒處于 Sleep 或中斷狀態,它就不能回應 JVM 的中斷請求,再運行到 Safe Point 上, 因此 JVM 引入了 Safe Region,
Safe Region 是指在一段代碼片段中,參考關系不會發生變化,在這個區域內的任意地方開始 GC 都是安全的, 執行緒在進入 Safe Region 的時候先標記自己已進入了 Safe Region,等到被喚醒時準備離開 Safe Region 時,先檢查能 否離開,如果 GC 完成了,那么執行緒可以離開,否則它必須等待直到收到安全離開的信號為止,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/105717.html
標籤:其他
