1. 程式人生 > >你還在看《深入理解Java虛擬機》的運行時數據模型嗎?

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

特點 kit 需要 由於 ron amp valueof hotspot 轉移

技術分享圖片

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

技術分享圖片

在這裏我們只針對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); 
}
}

結果如下:

技術分享圖片

證明 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());
}
}

結果如下:

技術分享圖片

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

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

為什麽移除永久代?

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

什麽是元空間(Metaspace),為什麽引入元空間

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

元空間的特點:

  • 每個加載器有專門的存儲空間。
  • 不會單獨回收某個類。
  • 元空間裏的對象的位置是固定的。
  • 如果發現某個加載器不再存活了,會把相關的空間整個回收。

總結

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

技術分享圖片

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