JDK8-廢棄永久代(PermGen)迎來元空間(Metaspace)
一、背景
轉載自:https://www.cnblogs.com/dennyzhangdd/p/6770188.html
1.1 永久代(PermGen)在哪裡?
根據,hotspot jvm結構如下(虛擬機器棧和本地方法棧合一起了):
上圖引自網路,但有個問題:方法區和heap堆都是執行緒共享的記憶體區域。
關於方法區和永久代:
在HotSpot JVM中,這次討論的永久代,就是上圖的方法區(JVM規範中稱為方法區)。《Java虛擬機器規範》只是規定了有方法區這麼個概念和它的作用,並沒有規定如何去實現它。在其他JVM上不存在永久代。
1.2 JDK8永久代的廢棄
JDK8 永久代變化如下圖:
1.新生代:Eden+From Survivor+To Survivor
2.老年代:OldGen
3.永久代(方法區的實現) : PermGen----->替換為Metaspace(本地記憶體中)
二、為什麼廢棄永久代(PermGen)
2.1 官方說明
參照JEP122:http://openjdk.java.net/jeps/122,原文擷取:
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.
即:移除永久代是為融合HotSpot JVM與 JRockit VM而做出的努力,因為JRockit沒有永久代,不需要配置永久代。
2.2 現實使用中易出問題
由於永久代記憶體經常不夠用或發生記憶體洩露,爆出異常java.lang.OutOfMemoryError: PermGen
三、深入理解元空間(Metaspace)
3.1元空間的記憶體大小
元空間是方法區的在HotSpot jvm 中的實現,方法區主要用於儲存類的資訊、常量池、方法資料、方法程式碼等。方法區邏輯上屬於堆的一部分,但是為了與堆進行區分,通常又叫“非堆”。
元空間的本質和永久代類似,都是對JVM規範中方法區的實現。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機器中,而是使用本地記憶體。,理論上取決於32位/64位系統可虛擬的記憶體大小。可見也不是無限制的,需要配置引數。
3.2常用配置引數
1.MetaspaceSize
初始化的Metaspace大小,控制元空間發生GC的閾值。GC後,動態增加或降低MetaspaceSize。在預設情況下,這個值大小根據不同的平臺在12M到20M浮動。使用Java -XX:+PrintFlagsInitial命令檢視本機的初始化引數
2.MaxMetaspaceSize
限制Metaspace增長的上限,防止因為某些情況導致Metaspace無限的使用本地記憶體,影響到其他程式。在本機上該引數的預設值為4294967295B(大約4096MB)。
3.MinMetaspaceFreeRatio
當進行過Metaspace GC之後,會計算當前Metaspace的空閒空間比,如果空閒比小於這個引數(即實際非空閒佔比過大,記憶體不夠用),那麼虛擬機器將增長Metaspace的大小。預設值為40,也就是40%。設定該引數可以控制Metaspace的增長的速度,太小的值會導致Metaspace增長的緩慢,Metaspace的使用逐漸趨於飽和,可能會影響之後類的載入。而太大的值會導致Metaspace增長的過快,浪費記憶體。
4.MaxMetasaceFreeRatio
當進行過Metaspace GC之後, 會計算當前Metaspace的空閒空間比,如果空閒比大於這個引數,那麼虛擬機器會釋放Metaspace的部分空間。預設值為70,也就是70%。
5.MaxMetaspaceExpansion
Metaspace增長時的最大幅度。在本機上該引數的預設值為5452592B(大約為5MB)。
6.MinMetaspaceExpansion
Metaspace增長時的最小幅度。在本機上該引數的預設值為340784B(大約330KB為)。
3.3測試並追蹤元空間大小
3.3.1.測試字串常量
public class StringOomMock {
static String base = "string";
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i=0;i< Integer.MAX_VALUE;i++){
String str = base + base;
base = str;
list.add(str.intern());
}
}
}
在eclipse中選中類--》run configuration-->java application--》new 引數如下:
由於設定了最大記憶體20M,很快就溢位,如下圖:
可見在jdk8中:
1.字串常量由永久代轉移到堆中。
2.持久代已不存在,PermSize MaxPermSize引數已移除。(看圖中最後兩行)
3.3.2.測試元空間溢位
根據定義,我們以載入類來測試元空間溢位,程式碼如下:
package jdk8;
import java.io.File;
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
/**
*
* @ClassName:OOMTest
* @Description:模擬類載入溢位(元空間oom)
* @author diandian.zhang
* @date 2017年4月27日上午9:45:40
*/
public class OOMTest {
public static void main(String[] args) {
try {
//準備url
URL url = new File("D:/58workplace/11study/src/main/java/jdk8").toURI().toURL();
URL[] urls = {url};
//獲取有關型別載入的JMX介面
ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
//用於快取類載入器
List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
while (true) {
//載入型別並快取類載入器例項
ClassLoader classLoader = new URLClassLoader(urls);
classLoaders.add(classLoader);
classLoader.loadClass("ClassA");
//顯示數量資訊(共載入過的型別數目,當前還有效的型別數目,已經被解除安裝的型別數目)
System.out.println("total: " + loadingBean.getTotalLoadedClassCount());
System.out.println("active: " + loadingBean.getLoadedClassCount());
System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
為了快速溢位,設定引數:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=80m,執行結果如下:
上圖證實了,我們的JDK8中類載入(方法區的功能)已經不在永久代PerGem中了,而是Metaspace中。可以配合JVisualVM來看,更直觀一些。
四、總結
本文講解了元空間(Metaspace)的由來和本質,常用配置,以及監控測試。元空間的大小是動態變更的,但不是無限大的,最好也時常關注一下大小,以免影響伺服器記憶體。
==================
參考:
相關文章
- 永久代和元空間的變化
- 為什麼用元空間替代永久代?
- 【深入理解JVM】方法區 永久代 元空間JVM
- JVM元空間Metaspace的記憶體結構JVM記憶體
- 用Jcmd命令分析虛擬機器Metaspace元空間虛擬機
- 歡迎來到devdede的空間!dev
- Java面試題虛擬機器為什麼使用元空間替換了永久代(JVM篇)Java面試題虛擬機JVM
- 2.5.6 建立預設的永久表空間
- 元宇宙是資料空間?大資料時代的新趨勢來了元宇宙大資料
- Vue 插槽 廢棄語法Vue
- ViewPager 要被廢棄?官方 ViewPager2 升級版來臨Viewpager
- go操作redis(已經廢棄)GoRedis
- JVM永久代JVM
- Android startActivityForResult()廢棄了,代替方案案例Android
- 眾創空間,符合時代需求
- 【眼界】NLP 迎來了黃金時代
- chrome + vi 純手工模式, 廢棄滑鼠。Chrome模式
- 特徵向量、神經元以及特徵空間特徵
- windows計劃任務的“等待空閒時間”已棄用Windows
- PHP7.4 新特性和廢棄的功能PHP
- php5.5CURL圖片上傳廢棄@PHP
- 線性代數應該這樣學6:積空間,商空間,多項式
- 張亞勤|物理世界和元空間(RSR)
- SLAM +機器學習迎來了“感知時代”SLAM機器學習
- Node.js 最早 npm 包 request 將被廢棄Node.jsNPM
- kotlin-android-extensions外掛也被廢棄了KotlinAndroid
- Java永久代去哪兒了Java
- 舊郵箱廢棄,GitHub 無法解綁帳號Github
- IDEA刪除已經廢棄不用的jdk選項IdeaJDK
- 高等代數 第三章 線性空間
- 深圳眾創空間,滿足新時代社交需求
- 16、表空間 建立表空間
- JavaScript即將迎來第三個時代或為終結時代? - swyxJavaScript
- 關於jvm的永久代會發生垃圾垃圾回收嗎?進來便知JVM
- 資料科學即將迎來“無程式碼”時代資料科學
- 潘雲鶴院士:人工智慧走向2.0的本質原因——人類世界正由兩元空間變成三元空間人工智慧
- JVM - 方法區(永久代)的垃圾回收JVM
- (七)永久代(方法區)的垃圾回收