爲什麼用元空間替代永久代?

永久代和元空間都是 HotSpot 虛擬機中的概念,HotSpot 虛擬機是 Sun JDK 和 Open JDK 中自帶的虛擬機,也是目前使用範圍最廣泛的 Java 虛擬機,當我們提到虛擬機時,大概率指的就是 HotSpot 虛擬機。

但從《Java 虛擬機規範》的層面來說,並沒有所謂的“永久代”和“元空間”等區域,詳見官方文檔:https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-2.html#jvms-2.5。《Java 虛擬機規範》只是規定了一個區域叫“方法區(Method Area)”,而 “永久代”和“元空間”是 HotSpot 虛擬機在不同的 JDK 版本下,對方法區的具體實現而已。這就好像,世界羽協規定羽毛球比賽必須要使用羽毛球拍(方法區),而中國羽毛球運動員,第一年使用的是紅雙喜牌的羽毛球拍(永久代),第二年使用的是李寧牌羽毛球拍(元空間)一樣。

那麼問題來了,永久代爲什麼被元空間給替代了?

1.官方答案

關於這個問題,官方在 JEP 122: Remove the Permanent Generation(移除永久代)中給出了答案,原文內容如下:

Motivation(動機)
This is part of the JRockit and Hotspot convergence effort. JRockit customers do not need to configure the permanent generation (since JRockit does not have a permanent generation) and are accustomed to not configuring the permanent generation.

以上內容翻譯成中文大意是:

這是 JRockit 虛擬機和 HotSpot 虛擬機融合工作的一部分。JRockit 客戶不需要配置永久層代(因爲 JRockit 沒有永久代),所以要移除永久代。

JRockit 是 Java 官方收購的一家號稱史上運行最快的 Java 虛擬機廠商,之後 Java 官方在 JDK 8 時將 JRockit 虛擬機和 HotSpot 虛擬機進行了整合。

PS:JEP 是 JDK Enhancement Proposal 的縮寫,翻譯成中文是 JDK 改進提案。你也可以把它理解爲 JDK 的更新文檔。

通過官方的描述,我們似乎找到了答案,也就是說,之所以要取消“永久代”是因爲 Java 官方收購了 JRockit,之後在將 JRockit 和 HotSpot 進行整合時,因爲 JRockit 中沒有“永久代”,所以把永久代給移除了

PS:上面的那段描述好像說的已經很清楚了,但又好像什麼也沒說。這就好比,我問你“爲什麼要買車?”,你說“別人都買車了,所以我要買車”,但爲什麼別人要買車?

2.背後的原因

上述給出了移除永久代的回答,但卻沒有給出背後的原因,那接下來我們就來討論一下,爲什麼要移除永久代?以及爲什麼要有元空間?

2.1 降低 OOM

當使用永久代實現方法區時,永久代的最大容量受制於 PermSize 和 MaxPermSize 參數設置的大小,而這兩個參數的大小又很難確定,因爲在程序運行時需要加載多少類是很難估算的,如果這兩個參數設置的過小就會頻繁的觸發 FullGC 和導致 OOM(Out of Memory,內存溢出)。

但是,當使用元空間替代了永久代之後,出現 OOM 的機率就被大大降低了,因爲元空間使用的是本地內存,這樣元空間的大小就只和本地內存的大小有關了,從而大大降低了 OOM 的問題。

2.2 降低運維成本

因爲元空間使用的是本地內存,這樣就無需運維人員再去專門設置和調整元空間的大小了。

3.方法區發展史

在 HotSpot 虛擬機中,方法區的實現經歷了以下 3 個階段:

  1. JDK 1.6 及之前:方法區使用永久代實現,靜態變量存放在永久代
  2. JDK 1.7 :“去永久代”的前置版本,還存在永久代,不過已經將字符串常量池和靜態變量從永久代移到了堆上
  3. JDK 1.8 及以後:無永久代,使用元空間(存放在本地內存中)實現方法區,常量保存在元空間,但字符串常量池和靜態變量依然保存在堆中

總結

永久代和元空間都是 HotSpot 虛擬機對《Java 虛擬機規範》中方法區的實現,在 JDK 1.8 之前 HotSpot 是使用永久代來實現方法區的,但這樣會導致 JVM 調優比較困難,且容易發生 OOM 的問題,而 JDK 1.8 及之後,使用的是元空間存放在本地內存中的方式來替代永久代的,這樣就降低了 OOM 發生的可能性,也是 JRockit 和 HotSpot 融合之後的改動之一。

參考 & 鳴謝

openjdk.org/jeps/122

本文已收錄到 Gitee 開源倉庫《Java 面試指南》,其中包含的內容有:Redis、JVM、併發、併發、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、設計模式、消息隊列等模塊。Java 面試有它就夠了:超全 Java 常見面試題,持續更新...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章