你還在看《深刻理解Java虛擬機》的運行時數據模型嗎?

學習JVM必看的書籍無疑是《深刻理解Java虛擬機》這本書了,在書中,關於運行時數據區域模型是這樣描述的: java

image.png

在這裏咱們只針對HotSpot VM來講,它是OracleJDK和OpenJDK中所帶的虛擬機,也是目前使用範圍最廣的Java虛擬機。在JDK7以前,這樣的模型是正確的。可是到了JDK8,如圖標紅的部分,作了一些優化。性能

什麼是方法區,什麼是永久代,運行時常量池又是什麼

  • 「方法區」(Method Area),是線程共享的區域,用於存儲已被虛擬機加載的類信息,常量,靜態變量等數據。首先咱們要知道,方法區是JVM的一種規範,是一個概念,而這個方法區的具體實現由各個虛擬機廠商去實現。
  • 「永久代」(Permanent Generation)就是HotSpot虛擬機對於方法區的實現,也僅僅是針HotSpot纔有的。
  • 「運行時常量池」是方法區的一部分。用於存放編譯期生成的各類字面量和符號引用。其特性是具有動態性。

優化一:字符串常量池從永久代劃到Java堆

因爲常量池具有動態性,在程序運行過程當中會有大量的字符串常量在運行時常量池裏產生,此時若是放在永久代,則沒法恰當的設定永久代的大小,容易出現性能問題和內存溢出。下面一個例子證實在JDK8中,字符串常量池已經放在堆中:學習

String.intern()方法的做用是返回一個字符串引用,引用的是字符串常量池中的字符串(字面量),咱們先來驗證一下這個方法:優化

public class StringConstantsPoolTest {
    public static void main(String[] args) {
        String str = "abc"; // str存儲在常量池
        String str2 = new String("abc");  // str2 存儲在堆中
        System.out.println(str == str2); // 結果爲false ,堆中的引用並不等於常量池中的引用
        str2 = str2.intern(); // 獲取str2在常量池中的引用
        System.out.println(str == str2); 
    }
}
複製代碼

結果以下: spa

image.png

證實 String.intern()方法返回了一個在常量池中的引用。 下面驗證字符串常量池在堆中: 設置JVM參數:線程

-Xms10m -Xmx10m -XX:-UseGCOverheadLimit代理

public static void main(String[] args) {
        List<String> list = new ArrayList();
        int i = 0;
        while(true){
            list.add(String.valueOf(i++).intern());
        }
    }
複製代碼

結果以下: code

image.png

 咱們看到這時報的是Java堆空間內存溢出,說明字符串常量池是在堆中,注意,此時僅僅是字符串常量池轉移到了堆中,可是運行時常量池依舊仍是在方法區裏cdn

優化二:移除了永久代,引入「元空間」(Metaspace)

爲何移除永久代?

  1. 方法區大小難以設定,容易發生內存溢出。永久代會存放Class的相關信息,通常這些信息在編譯期間就能肯定大小。可是若是是在一些須要動態生成大量Class的應用中,如:Spring的動態代理、大量的JSP頁面或動態生成JSP頁面等,因爲方法區的大小在一開始就要分配好,所以就能難肯定大小,容易出現內存溢出
  2. GC複雜且效率低。方法區存儲了類的元數據信息和各類常量,它的內存回收目標理應當是對這些類型的卸載和常量的回收。但因爲這些數據被類的實例引用,卸載條件變得複雜且嚴格,回收不當會致使堆中的類實例失去元數據信息和常量信息。所以,回收方法區內存不是一件簡單高效的事情。
  3. 促進HotSpot JVM與JRockit VM的融合。JRockit沒有方法區,移除永久代能夠促進HotSpot JVM與JRockit VM的融合。

什麼是元空間(Metaspace),爲何引入元空間

元空間的本質和永久代相似,都是對JVM規範中方法區的實現。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存。所以,默認狀況下,元空間的大小僅受本地內存限制對象

元空間的特色:

  1. 每一個加載器有專門的存儲空間。
  2. 不會單獨回收某個類。
  3. 元空間裏的對象的位置是固定的。
  4. 若是發現某個加載器再也不存活了,會把相關的空間整個回收。

總結

最終JVM(HotSpot)運行時數據區域模型以下:

image.png
相關文章
相關標籤/搜索