1.背景

2.为什么废弃永久代(PermGen)

3.深入理解元空间(Metaspace)

4.总结

========正文分割线=====

一、背景

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来看,更直观一些。

四、总结

本文讲解了元空间(Metaspace)的由来和本质,常用配置,以及监控测试。元空间的大小是动态变更的,但不是无限大的,最好也时常关注一下大小,以免影响服务器内存。

转载于:https://www.cnblogs.com/zhulibin2012/p/8994178.html

深入理解java虚拟机---JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)(十二)相关推荐

  1. java 8 永久代_Java8内存结构—永久代(PermGen)和元空间(Metaspace)

    本文转载 一.JVM 内存结构 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是 ...

  2. java堆 permgen_Java8内存模型—永久代(PermGen)和元空间(Metaspace)

    一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫&q ...

  3. Java8内存模型—永久代(PermGen)和元空间(Metaspace)

    一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫&q ...

  4. 永久代内存java_Java8内存模型—永久代(PermGen)和元空间(Metaspace)

    一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫&q ...

  5. Java8:永久代(PermGen)和元空间(Metaspace)

    一.PermGen(永久代) 绝大部分 Java 程序员应该都见过 "java.lang.OutOfMemoryError: PermGen space "这个异常.这里的 &qu ...

  6. jvm系列二:Java8内存模型-永久代(PermGen)和元空间(Metaspace)

    原文地址:https://www.cnblogs.com/paddix/p/5309550.html 一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地 ...

  7. 深入理解Java虚拟机(周志明第三版)- 第十二章:Java内存模型与线程

    系列文章目录 第一章: 走近Java 第二章: Java内存区域与内存溢出异常 第三章: Java垃圾收集器与内存分配策略 并发处理的广泛应用是Amdahl定律代替摩尔定律成为计算机性能发展源动力的根 ...

  8. Davids原理探究:JDK8将永久代(PermGen)替换为元空间(MetaSpace)的原因

    文章目录 JDK8将永久代(PermGen)替换为元空间(MetaSpace)的原因 什么是方法区 永久代产生的原因 将永久代替换为源空间的原因 JDK8将永久代(PermGen)替换为元空间(Met ...

  9. java虚拟机-JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

    一.背景 1.1 永久代(PermGen)在哪里? 根据,hotspot jvm结构如下(虚拟机栈和本地方法栈合一起了): 上图引自网络,但有个问题:方法区和heap堆都是线程共享的内存区域. 关于方 ...

  10. 《深入理解java虚拟机》笔记2——GC算法与内存分配策略

    说起垃圾收集(Garbage Collection, GC),想必大家都不陌生,它是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如Sca ...

最新文章

  1. 日常工作问题解决:centos/linux系统如何检测端口是否打开
  2. python的os模块批量获取目标路径下的文件名
  3. ELF 文件 动态链接 - 地址无关代码(GOT)
  4. leetcode-54 螺旋矩阵
  5. mysql memcached 使用场景_memcache 应用场景
  6. not supported between instances of 'SafeText' and 'int' 问题出现以及解决
  7. JavaScript 数组拼接打印_JavaScript数组_创建数组_一维数组_length(二十三)
  8. jstack处理Java中CPU100%的思路流程
  9. freebsd 自动启动服务器,教程/FreeBSD启动脚本
  10. wince系统usb刷机工具_中兴B860AV1.2-S905L刷机救砖教程,喜欢的分享一下
  11. Loadrunner11 下载、安装与破解
  12. Clearcase, SVN, Git之我见
  13. 联想Y9000P-2022款踩坑指南 加装固态和内存 win10系统安装
  14. GAN 生成对抗网络 10-6 Tips for improving GAN
  15. python制作ppt改变颜色标题_ppt-页面大小和颜色更改
  16. 【辗转反侧不得眠,心中疑惑何时解】---前段时间安装了showdoc,由于停电忘记怎么安装的了--稀里糊涂的重启showdoc
  17. Netty实现聊天室
  18. javascript当中options的用法
  19. 【15.罗马数字转整数】
  20. Linux Python离线下载模块

热门文章

  1. 直接安装的Qt 5如何调试到源码中
  2. 如何让你的Android SDK下载或者升级快如闪电
  3. cmd命令配置MySQL
  4. Linux中RAID机制的实现
  5. Intel-VT 与虚拟化限制
  6. 今天开始清理个人计算机资料了
  7. IDEA 这个小技巧太实用了。。
  8. 一次线上商城系统高并发优化,涨姿势了~
  9. 微服务的简介和技术栈,太牛逼了!
  10. 这款中间件支持多线程,居然吊打牛B的 Redis!