java虚拟机-JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)
一、背景
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.测试字符串常量


1 public class StringOomMock {
2 static String base = "string";
3
4 public static void main(String[] args) {
5 List<String> list = new ArrayList<String>();
6 for (int i=0;i< Integer.MAX_VALUE;i++){
7 String str = base + base;
8 base = str;
9 list.add(str.intern());
10 }
11 }
12 }


在eclipse中选中类--》run configuration-->java application--》new 参数如下:

由于设定了最大内存20M,很快就溢出,如下图:

可见在jdk8中:
1.字符串常量由永久代转移到堆中。
2.持久代已不存在,PermSize MaxPermSize参数已移除。(看图中最后两行)
3.3.2.测试元空间溢出
根据定义,我们以加载类来测试元空间溢出,代码如下:


1 package jdk8;
2
3 import java.io.File;
4 import java.lang.management.ClassLoadingMXBean;
5 import java.lang.management.ManagementFactory;
6 import java.net.URL;
7 import java.net.URLClassLoader;
8 import java.util.ArrayList;
9 import java.util.List;
10
11 /**
12 *
13 * @ClassName:OOMTest
14 * @Description:模拟类加载溢出(元空间oom)
15 * @author diandian.zhang
16 * @date 2017年4月27日上午9:45:40
17 */
18 public class OOMTest {
19 public static void main(String[] args) {
20 try {
21 //准备url
22 URL url = new File("D:/58workplace/11study/src/main/java/jdk8").toURI().toURL();
23 URL[] urls = {url};
24 //获取有关类型加载的JMX接口
25 ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
26 //用于缓存类加载器
27 List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
28 while (true) {
29 //加载类型并缓存类加载器实例
30 ClassLoader classLoader = new URLClassLoader(urls);
31 classLoaders.add(classLoader);
32 classLoader.loadClass("ClassA");
33 //显示数量信息(共加载过的类型数目,当前还有效的类型数目,已经被卸载的类型数目)
34 System.out.println("total: " + loadingBean.getTotalLoadedClassCount());
35 System.out.println("active: " + loadingBean.getLoadedClassCount());
36 System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());
37 }
38 } catch (Exception e) {
39 e.printStackTrace();
40 }
41 }
42 }


为了快速溢出,设置参数:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=80m,运行结果如下:

上图证实了,我们的JDK8中类加载(方法区的功能)已经不在永久代PerGem中了,而是Metaspace中。可以配合JVisualVM来看,更直观一些。
java虚拟机-JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)的更多相关文章
- Java8内存模型—永久代(PermGen)和元空间(Metaspace)(转)
Java8内存模型—永久代(PermGen)和元空间(Metaspace) 查看原文点击传送门:http://www.cnblogs.com/paddix/p/5309550.html 提示:本文做了 ...
- (转)Java8内存模型—永久代(PermGen)和元空间(Metaspace)
背景:介绍java8中永久代到元空间的转变. Java8内存模型—永久代(PermGen)和元空间(Metaspace) 一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法 ...
- 转:Java8内存模型—永久代(PermGen)和元空间(Metaspace)
一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫“栈 ...
- Java8内存模型—永久代(PermGen)和元空间(Metaspace)
一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫“栈 ...
- Java8内存结构—永久代(PermGen)和元空间(Metaspace)
本文转载 作者:liuxiaopeng 博客地址:https://www.cnblogs.com/paddix/p/5309550.html 一.JVM 内存结构 根据 JVM 规范,JVM 内存共分 ...
- java 8中撤销永久代,引入元空间
撤销永久代,引入元空间: 在 JDK 1.8 中,HotSpot 已经没有 “PermGen space”这个空间了,取而代之是一个叫做 Metaspace(元空间) 的东西. Java7中已经将字符 ...
- 深入理解java虚拟机---JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)(十二)
引用:https://www.cnblogs.com/yulei126/p/6777323.html JDK8-废弃永久代(PermGen)迎来元空间(Metaspace) 1.背景 2.为什么废 ...
- JVM虚拟机21: 1.8中废弃永久代(PermGen)迎来元空间(Metaspace)
1.JDK8永久代的废弃 JDK8 永久代变化如下图: 1.新生代:Eden+From Survivor+To Survivor 2.老年代:OldGen 3.永久代(方法区的实现) : PermGe ...
- jdk源码剖析五:JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)
目录 1.背景 2.为什么废弃永久代(PermGen) 3.深入理解元空间(Metaspace) 4.总结 ========正文分割线===== 一.背景 1.1 永久代(PermGen)在哪里? 根 ...
随机推荐
- 构建自己的PHP框架(composer)
完整项目地址:https://github.com/Evai/Aier Composer 利用 PSR-0 和 PSR-4 以及 PHP5.3 的命名空间构造了一个繁荣的 PHP 生态系统.Compo ...
- Altera公司高速PCB布线指南
来至Altera公司的高速PCB布线指南,该文档言简意赅,深入浅出,对于日常高速PCB布局布线中经常碰到的一些问题进行了解析.例如:板材的选择,介电常数及损耗因子对高速高频线路的影响,传输线,阻抗控制 ...
- crawler_正则表达式零宽断言
在使用正则表达式时,有时我们需要捕获的内容前后必须是特定内容,但又不捕获这些特定内容的时候,零宽断言就起到作用了. (?=exp):零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp. ...
- WPF不明内存泄露已解决,白头发也没了
原文:WPF不明内存泄露已解决,白头发也没了 在使用OpenExpressApp进行WPF应用开发过程中遇到多个内存泄漏的地方,在上一篇中求助了一个内存泄露问题[WPF不明内存泄露原因,头发都白了几根 ...
- Tab切换效果的实现
<!--引用jquery和bootstrap--> <link rel="stylesheet" href="~/Content/bootstrap.m ...
- wpf border内部元素内边角溢出问题 裁剪效果
效果图 <Grid> <Border BorderThickness=" BorderBrush="#3c4d72" CornerRadius=&quo ...
- 关于QSocket的释放的一个需要注意的情况(必须先断开连接)
最近在用QtNetwork编写服务器程序进行TCP/IP通信,大体过程如下: 1. 创建一个QTcpServer实例,监听目标IP和端口: 2. 一旦监听到有连接,获取和客户端之间的socket: 3 ...
- 利用winIO3.0进行windows10 64bit端口读取
一.winIO介绍 WinIO程序库允许在32位的Windows应用程序中直接对I/O端口和物理内存进行存取操作.通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,它绕过了Windows系统的保 ...
- Use Spring @Scheduled To Achieve Timing Task
Today I have a chance to use the @Scheduled to achieve a timing task.It is useful.Anyway,it was the ...
- mysql三种修改密码的方式
[root@MySQL ~]# mysqladmin -uroot -proot -S /data/3307/mysql.sock password '123'; 其中-p是现在的密码,passwor ...