java的常量池

fall_hat發表於2020-11-03

java常量池

java的常量池有三個概念,靜態常量池,執行時常量池,字串常量池
JVM在執行某個類的時候,必須經過載入、連線、初始化,而連線又包括驗證、準備、解析三個階段。
靜態常量池用於存放編譯期生成的各種字面量和符號引用,而當類載入到記憶體中後,jvm就會將靜態常量池中的內容存放到執行時常量池中。而字串常量池存的是引用值,其存在於執行時常量池之中。

靜態常量池

靜態常量池也就是Class檔案中的常量池。

靜態常量池用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後存放到方法區的執行時常量池中。其中符號引用其實引用的就是常量池裡面的字串,但符號引用不是直接儲存字串,而是儲存字串在常量池裡的索引。

當Class檔案被載入完成後,java虛擬機器會將靜態常量池裡的內容轉移到執行時常量池裡,在靜態常量池的符號引用有一部分是會被轉變為直接引用的,比如說類的靜態方法或私有方法,例項構造方法,父類方法,這是因為這些方法不能被重寫其他版本,所以能在載入的時候就可以將符號引用轉變為直接引用,而其他的一些方法是在這個方法被第一次呼叫的時候才會將符號引用轉變為直接引用的。

執行時常量池

執行時常量池(Runtime Constant Pool)是方法區的一部分,在jdk8之後,執行時常量池在堆中。對於執行時常量池,Java虛擬機器規範沒有做任何細節的要求,不同的提供商實現的虛擬機器可以按照自己的需要來實現這個記憶體區域。不過,一般來說,除了儲存Class檔案中描述的符號引用外,還會把翻譯出來的直接引用也儲存在執行時常量池中。
執行時常量池還有個更重要的的特徵:動態性。Java要求,編譯期的常量池的內容可以進入執行時常量池,執行時產生的常量也可以放入池中。常用的是String類的intern()方法。
既然執行時常量池是方法區的一部分自然會受到方法區記憶體的限制,當常量池無法再申請到記憶體時會丟擲OutOfMemoryError異常。

字串常量池

字串常量池存在堆中(在JDK7之前存在執行時常量池之中,在JDK7已經將其轉移到堆中)。

使用字串常量池,每當我們使用字面量(String s=”1”;)建立字串常量時,JVM會首先檢查字串常量池,如果該字串已經存在常量池中,那麼就將此字串物件的地址賦值給引用s(引用s在Java棧中)。如果字串不存在常量池中,就會例項化該字串並且將其放到常量池中,並將此字串物件的地址賦值給引用s(引用s在Java棧中)。

使用字串常量池,每當我們使用關鍵字new(String s=new String(”1”);)建立字串常量時,JVM會首先檢查字串常量池,如果該字串已經存在常量池中,那麼不再在字串常量池建立該字串物件,而直接堆中建立該物件的副本,然後將堆中物件的地址賦值給引用s,如果字串不存在常量池中,就會例項化該字串並且將其放到常量池中,然後在堆中建立該物件的副本,然後將堆中物件的地址賦值給引用s。

在JDK8版本:

靜態常量池在Class檔案中。

JVM已經將執行時常量池從方法區中移了出來,在Java 堆(Heap)中開闢了一塊區域存放執行時常量池。同時永久代被移除,以元空間代替。元空間並不在虛擬機器中,而是使用本地記憶體。因此,預設情況下,元空間的大小僅受本地記憶體限制。其主要用於存放一些後設資料。

字串常量池存在於Java堆中。

相關文章