一:Metaspace介绍

我们都知道jdk8之前有perm这一整块内存来存klass等信息,我们的参数里也必不可少地会配置-XX:PermSize以及-XX:MaxPermSize来控制这块内存的大小,jvm在启动的时候会根据这些配置来分配一块连续的内存块,但是随着动态类加载的情况越来越多,这块内存我们变得不太可控,到底设置多大合适是每个开发者要考虑的问题,如果设置太小了,系统运行过程中就容易出现内存溢出,设置大了又总感觉浪费,尽管不会实质分配这么大的物理内存。基于这么一个可能的原因,于是metaspace出现了,希望内存的管理不再受到限制,也不要怎么关注元数据这块的OOM问题,虽然到目前来看,也并没有完美地解决这个问题。

或许从JVM代码里也能看出一些端倪来,比如MaxMetaspaceSize默认值很大,CompressedClassSpaceSize默认也有1G,从这些参数我们能猜到metaspace的作者不希望出现它相关的OOM问题。

二:Metaspace的空间组成

metaspace其实由两大部分组成

Klass Metaspace
NoKlass Metaspace
//加入Java开发交流君样:756584822一起吹水聊天
Klass Metaspace就是用来存klass的,klass是我们熟知的class文件在jvm里的运行时数据结构,不过有点要提的是我们看到的类似A.class其实是存在heap里的,是java.lang.Class的一个对象实例。这块内存是紧接着Heap的,和我们之前的perm一样,这块内存大小可通过-XX:CompressedClassSpaceSize参数来控制,这个参数前面提到了默认是1G,但是这块内存也可以没有,假如没有开启压缩指针就不会有这块内存,这种情况下klass都会存在NoKlass Metaspace里,另外如果我们把-Xmx设置大于32G的话,其实也是没有这块内存的,因为会这么大内存会关闭压缩指针开关。还有就是这块内存最多只会存在一块。

NoKlass Metaspace专门来存klass相关的其他的内容,比如method,constantPool等,这块内存是由多块内存组合起来的,所以可以认为是不连续的内存块组成的。这块内存是必须的,虽然叫做NoKlass Metaspace,但是也其实可以存klass的内容,上面已经提到了对应场景。

Klass Metaspace和NoKlass Mestaspace都是所有classloader共享的,所以类加载器们要分配内存,但是每个类加载器都有一个SpaceManager,来管理属于这个类加载的内存小块。如果Klass Metaspace用完了,那就会OOM了,不过一般情况下不会,NoKlass Mestaspace是由一块块内存慢慢组合起来的,在没有达到限制条件的情况下,会不断加长这条链,让它可以持续工作。

CompressedClassSpace和metaspace之间的关系
虽然前面提到CompressedClassSpace由参数-XX:CompressedClassSpaceSize参数来控制,而且默认1G,但是这并不意味着这块内存的大小不设置就是1G的大小了。我们先来做个小测试。

1:VM Options不写任何参数

我们使用下面的指令找到这个pid

jps -l

然后使用下面命令指令查看参数的默认值

jinfo -flag CompressedClassSpaceSize 32224
查出来的值换算后刚好是1G。

最小最大的Metaspace大小如下,最大值可以认为无穷大了,最小值是21M
2:设置VM参数
此时 CompressedClassSpaceSize大小变成:60M
我们虽然没有显示设置 CompressedClassSpaceSize大小,但是它已经变了。

这是因为 CompressedClassSpaceSize的大小是由:MaxMetaspaceSize,InitialBootClassLoaderMetaspaceSize,CompressedClassSpaceSize这三个参数共同影响的结果

具体就是:

min_metaspace_sz 加CompressedClassSpaceSize大于 MaxMetaspaceSize的时候,CompressedClassSpaceSize就强制被设置为(MaxMetaspaceSize - min_metaspace_sz)。

min_metaspace_sz是VIRTUALSPACEMULTIPLIER * InitialBootClassLoaderMetaspaceSize的乘积。VIRTUALSPACEMULTIPLIER是2,InitialBootClassLoaderMetaspaceSize是根据-XX:InitialBootClassLoaderMetaspaceSize的参数设置的。
//加入Java开发交流君样:756584822一起吹水聊天
-XX:InitialBootClassLoaderMetaspaceSize64位下默认4M,32位下默认2200K,metasapce前面已经提到主要分了两大块,Klass Metaspace以及NoKlass Metaspace,而NoKlass Metaspace是由一块块内存组合起来的,这个参数决定了NoKlass Metaspace的第一个内存Block的大小,即2*InitialBootClassLoaderMetaspaceSize,同时为bootstrapClassLoader的第一块内存chunk分配了InitialBootClassLoaderMetaspaceSize的大小。

InitialBootClassLoaderMetaspaceSize默认4M也可以看到
所以加了VM参数之后CompressedClassSpaceSize=68-2*4=60M。

三:GC日志最后输出的 :Metaspace used 2425K, capacity 4498K, committed

4864K, reserved 1056768K代表啥
在官网上:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/considerations.html 有下面一段话描述这个问题。

In the line beginning with Metaspace, the used value is the amount of space used for loaded classes. The capacity value is the space available for metadata in currently allocated chunks. The committed value is the amount of space available for chunks. The reserved value is the amount of space reserved (but not necessarily committed) for metadata. The line beginning with class space line contains the corresponding values for the metadata for compressed class pointers.
先看一张图:
首先可以看到的是,这些used,capacity,committed和reserved并不纯粹是JVM的概念,它和操作系统相关。

先来看committed和reserved。reserved是指,操作系统已经为该进程“保留”的。所谓的保留,更加接近一种记账的概念,就是操作系统承诺说一大块连续的内存已经是你这个进程的了。注意的是,这里强调的是连续的内存,并且强调的是一种名义归属。那么实际上这一大块内存有没有真实对应的物理内存呢?答案是不知道。

那么什么时候才知道呢?等进程committed的时候。当进程真的要用这个连续地址空间的时候,操作系统才会分配真正的内存。所以,这也就是意味着,这个过程会失败。

used和capacity就是JVM的概念了。这两个概念非常接近JVM一些集合框架的概念。一些Java集合框架,比如某种List的实现,会有size和capacity的概念。比如说ArrayList的实现里面就有capacity和size的概念。假如说我创建了一个可以存放20个元素的ArrayList,但是我实际上只放了10个元素,那么capacity就是20,而size就是10.这里的size和used就是一个概念。那么“元素”则是一个个内存块"block“。
//加入Java开发交流君样:756584822一起吹水聊天
capacity和committed的关系也可以此类比,只不过capacity反而对应到used,committed对应到capacity,而所谓的”元素“,就是chunk。

至于class space,要记住的是,metaspace并不是全部用来放类对象的。比如说,因为每一个ClassLoader都被分配了一块内存,这块内存可能并没有被用完,于是就会有一些内存碎片;metaspace还需要放所谓静态变量。所以,class space是指实际上被用于放class的那块内存的和。

注意:

Metaspace由一个或多个虚拟空间组成,虚拟空间的分配单元是Chunk,其中Chunk使用列表进行维护。

当使用一个classLoader加载一个类时,过程如下:

1、当前classLoader是否有对应的Chunk且有足够的空间。

2、查找空闲列表中的有没有空闲的Chunk。

3、如果没有,就从当前虚拟空间中分配一个新的Chunk,这个时候会把对应的内存进行Commit,这个动作就是提交。

4、如果当前虚拟空间不足,则预留(reserves)一个新的虚拟空间。

reserved是jvm启动时根据参数和操作系统预留的内存大小。

committed是指那些被commit的Chunk大小之和;
//加入Java开发交流君样:756584822一起吹水聊天
capacity是指那些被实际分配的Chunk大小之和;

因为有GC的存在,有些Chunk的数据可能会被回收,那么这些Chunk属于committe的一部分,但不属于capacity

另外,这些被分配的Chunk,基本很难被100%用完,存在碎片内存的情况,这些Chunk实际被使用的内存之和即used的大小;

所以,如何一个服务中被代理的方法特别特别多,就可能存在创建特别特别多的classLoader对象,一个classLoader对象至少需要一个Chunk,这个Chunk可能只放一个class信息,那么就存在特别特别严重的内存碎片,继而就存在一个隐患,可能发生特别频繁的FGC,而且是由Metaspace不足引起的

最新2020整理收集的一些高频面试题(都整理成文档),有很多干货,包含mysql,netty,spring,线程,spring cloud、jvm、源码、算法等详细讲解,也有详细的学习规划图,面试题整理等,需要获取这些内容的朋友请加Q君样:756584822

JVM之Metaspace解密相关推荐

  1. JVM源码分析之Metaspace解密

    本文来自:HeapDump性能社区 PerfMa(笨马网络)官网 概述 metaspace,顾名思义,元数据空间,专门用来存元数据的,它是jdk8里特有的数据结构用来替代perm,这块空间很有自己的特 ...

  2. JVM的Metaspace,JAVA8以前是Permanent Area

    JVM为啥从Permanent Area转向Metaspace呢? 1. Parmanent容易出现OOM. 2. GC,Parmanent发生的也是Full GC. Metaspace的2个特征: ...

  3. jvm系列(十一):Java 8-从持久代到metaspace

    原文出处:http://blog.csdn.net/wang8118/article/details/45765869 Java 8介绍了一些新语言以及运行时新特点.其中一个特点便是完全移除了持久代( ...

  4. JAVA之JVM知识汇总

    Java虚拟机(JVM)你只要看这一篇就够了!_Java笔记-CSDN博客_jvm JVM GC 机制与性能优化_橙子wj的博客-CSDN博客 为什么新生代内存需要有两个Survivor区_橙子wj的 ...

  5. 由「Metaspace容量不足触发CMS GC」从而引发的思考

    转载自  由「Metaspace容量不足触发CMS GC」从而引发的思考 某天早上,毛老师在群里问「cat 上怎么看 gc」. 好好的一个群 看到有 GC 的问题,立马做出小鸡搓手状. 之后毛老师发来 ...

  6. JVM架构和GC垃圾回收机制详解

    JVM架构图分析 下图:参考网络+书籍,如有侵权请见谅 (想了解Hadoop内存溢出请看: Hadoop内存溢出(OOM)分类.参数调优化) JVM被分为三个主要的子系统 (1)类加载器子系统(2)运 ...

  7. 京东必考JVM 问题诊断快速入门

    JVM 问题诊断快速入门 JVM 全称为 Java Virtual Machine,翻译为中文 "Java 虚拟机".本文中的JVM主要指 Oracle 公司的 HotSpot V ...

  8. 聊聊jvm的CompressedClassSpace

    序 本文主要研究一下jvm的CompressedClassSpace CompressedClassSpace java8移除了permanent generation,然后class metadat ...

  9. 一、什么是JVM以及JVM的内存区域

    一.什么是JVM? 定义 Java Virtual Machine,JAVA程序的运行环境(JAVA二进制字节码的运行环境) 好处 一次编写,到处运行 自动内存管理,垃圾回收机制 数组下标越界检查 比 ...

最新文章

  1. mysql-connector-net-6.7.4.msi,在ActiveReports中使用MySQL数据库
  2. 在已交出句柄的QWidget上叠加透明形状
  3. 20个最强的基于浏览器的在线代码编辑器 - OPEN资讯
  4. IIS日志分析方法及工具
  5. [CQOI2015]选数(数论分块+杜教筛)
  6. 【Java】java.util.Objects 工具类方法研究
  7. Spring框架——day04参数校验和文件上传
  8. ArcGIS学习总结(12)——拓扑检查和修正
  9. AD7705应用总结:
  10. c语言二进制转十六进制代码,C语言--二进制转十六进制
  11. [转]Phoenix综述(史上最全Phoenix中文文档)
  12. vue 身份证格式校验
  13. 网页打开慢的服务器网络原因,网页打开很慢的原因有哪些 如何处理
  14. mindspore| lenet模型 推理过程记录
  15. pandas处理字符串
  16. linux查询主机信息命令,用来获取Linux主机信息的5个常用命令
  17. c# picturebox 刷新_c# – 更新PictureBox时可能导致ArgumentException的原因是什么?
  18. 20190123——一气化三清 Java中介者模式
  19. target overrides the `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES` build setting defined in `Pods/Target S
  20. arcgis地图怎么标注当前位置

热门文章

  1. EN 45545-2:2020 T11烟毒性检测
  2. git学习之Linux安装Git
  3. SCTF 2019 re部分题解(持续更新中)
  4. OpenPifPaf decode源码解析
  5. 股票类网站php,php 股票信息查询类
  6. Github建仓传码
  7. ESXi无法直通显卡
  8. 云计算、公有云、私有云、混合云等
  9. 复旦大学王思远:基于事实的自动问题生成研究
  10. SCrapy爬虫大战京东商城