https://blog.csdn.net/sjmz30071360/article/details/89456177

(Metaspace)

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.  
    import java.util.ArrayList;
  2.  
    import java.util.List;
  3.  
     
  4.  
    public class StringTest {
  5.  
    static String base = "string";
  6.  
     
  7.  
    public static void main(String[] args) {
  8.  
     
  9.  
    List<String> list = new ArrayList<String>();
  10.  
    for (int i=0;i< Integer.MAX_VALUE;i++){
  11.  
    String str = base + base;
  12.  
    base = str;
  13.  
    list.add(str.intern());
  14.  
    }
  15.  
    }
  16.  
    }

由于设定了最大内存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)的由来和本质,常用配置,以及监控测试。元空间的大小是动态变更的,但不是无限大的,最好也时常关注一下大小,以免影响服务器内存。

JDK1.8为什么废弃永久代【一篇就够】[z]的更多相关文章

  1. JVM虚拟机21: 1.8中废弃永久代(PermGen)迎来元空间(Metaspace)

    1.JDK8永久代的废弃 JDK8 永久代变化如下图: 1.新生代:Eden+From Survivor+To Survivor 2.老年代:OldGen 3.永久代(方法区的实现) : PermGe ...

  2. 深入理解JVM虚拟机1:JVM内存的结构与消失的永久代

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...

  3. JVM年轻代、年老代、永久代

    年轻代: HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫From和To),每次新创建对象时,都会分配到Eden区,当Eden区没有足够的空间进行分配时,虚拟 ...

  4. jdk源码剖析五:JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

    目录 1.背景 2.为什么废弃永久代(PermGen) 3.深入理解元空间(Metaspace) 4.总结 ========正文分割线===== 一.背景 1.1 永久代(PermGen)在哪里? 根 ...

  5. JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

    1.背景 2.为什么废弃永久代(PermGen) 3.深入理解元空间(Metaspace) 4.总结 ========正文分割线===== 一.背景 1.1 永久代(PermGen)在哪里? 根据,h ...

  6. JVM深入:JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)(转)

    转载自:https://www.cnblogs.com/yulei126/p/6777323.html 1.背景 2.为什么废弃永久代(PermGen) 3.深入理解元空间(Metaspace) 4. ...

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

    引用:https://www.cnblogs.com/yulei126/p/6777323.html JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)   1.背景 2.为什么废 ...

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

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

  9. Java堆的结构是什么样子的?什么是堆中的永久代(Perm Gen space)?

    JVM的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存.它在JVM启动的时候被创建.对象所占的堆内存是由自动内存管理系统也就是垃圾收集器回收. 堆内存是由存活和死亡的对象组成的.存活的对象是应 ...

随机推荐

  1. [Abp vNext微服务实践] - vue-element-admin登录一

    简介 之前的技术路线本来是angular的,后来经过一段时间的开发还是打算选择vue,原因是vue简单丰富,尽管angular规范强大,但是组件库都不太符合国人风格.看到GitHub上Vue Elem ...

  2. Istio技术与实践04:最佳实践之教你写一个完整的Mixer Adapter

    Istio内置的部分适配器以及相应功能举例如下: circonus:微服务监控分析平台. cloudwatch:针对AWS云资源监控的工具. fluentd:开源的日志采集工具. prometheus ...

  3. Java NIO 学习笔记一

    缓冲区操作 进程执行I/O操作,归结起来就是向操作系统发出请求,它要么把缓存区例的数据排干(写),要么用数据把数据区填满(读).进程使用这一机制处理所有数据进出操作. 进程使用read()系统调用,要 ...

  4. MYSQL安全模式SQL语法需要注意的地方

    MYSQL安全模式 Mysql版本: 背景: 为了避免在执行delete.update将全表数据清空或者覆盖修改,在新项目营销云中开启了mysql的安全模式. 安全模式要求不能对非主键的条件查询做up ...

  5. Redis入门(三)——主从服务器配置

    当数据量变得庞大的时候,读写分离还是很有必要的.同时避免一个redis服务宕机,导致应用宕机的情况,我们启用sentinel(哨兵)服务,实现主从切换的功能.redis提供了一个master,多个sl ...

  6. javascript代码模块化解决方案

    我们用模块化的思想进行网页的编写是为了更好的管理我们的项目,模块与模块之间是独立存在的,每个模块可以独立的完成一个子功能. 一.服务器和桌面环境中的Javascript代码模块化:CommonJS M ...

  7. 2018-2019 ACM-ICPC Brazil Subregional Programming Contest B. Marbles(博弈)

    题目链接:https://codeforc.es/gym/101908/problem/B 题意:两个人玩游戏,有 n 块石头,初始坐标为(x,y),一次操作可以将一块石头移动到(x - u,y),( ...

  8. Codeforces Round #587 (Div. 3) D. Swords

    链接: https://codeforces.com/contest/1216/problem/D 题意: There were n types of swords in the theater ba ...

  9. nginx静态资源配置(转发)

    传统的web项目,一般都将静态资源存放在 webroot的目录下,这样做很方便获取静态资源,但是如果说web项目很大,用户很多,静态资源也很多时,服务器的性能 或许就会很低下了.这种情况下一般都会需要 ...

  10. jQuery系列(五):jQuery操作input的value值

    表单控件是重中之重,因为一旦牵扯到数据交互,离不开form表单的使用,比如用户的注册登录功能等. jQuery操作表单控件的方法: $(selector).val()//设置值和获取值 1.实例代码 ...