前言

很多开发者都在其系统中见过“java.lang.OutOfMemoryError: PermGen space”这一问题。这往往是由类加载器相关的内存泄漏以及新类加载器的创建导致的,通常出现于代码热部署时。相对于正式产品,该问题在开发机上出现的 频率更高,在产品中最常见的“问题”是默认值太低了。常用的解决方法是将其设置为256MB或更高。

JDK8 HotSpot JVM 将移除永久区,使用本地内存来存储类元数据信息并称之为:元空间(Metaspace)。这意味着不会再有java.lang.OutOfMemoryError: PermGen问题,也不再需要你进行调优及监控内存空间的使用。

总结:
PermGen空间状况:这部分内存空间将全部移除。JVM的参数:PermSize 和 MaxPermSize 会被忽略并给出警告(如果在启用时设置了这两个参数)。

Metaspace 容量:默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小)。新参数(MaxMetaspaceSize)用于限制本地内存分配给类元数据的大小。如果没有指定这个参数,元空间会在运行时根据需要动态调整。

另外,对于僵死的类及类加载器的垃圾回收将在元数据使用达到“MaxMetaspaceSize”参数的设定值时进行。适时地监控和调整元空间对于减小垃圾回收频率和减少延时是很有必要的。持续的元空间垃圾回收说明,可能存在类、类加载器导致的内存泄漏或是大小设置不合适。

PermGen space简单介绍

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,说说为什么会内存益出:这一部分用于存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域,它和和存放Instance的Heap区域不同,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。这种错误常见在web服务器对JSP进行pre compile的时候。

JVM 种类有很多,比如 Oralce-Sun Hotspot, Oralce JRockit, IBM J9, Taobao JVM等等。当然武林盟主是Hotspot了,这个毫无争议。需要注意的是,PermGen space是Oracle-Sun Hotspot才有,JRockit以及J9是没有这个区域。

元空间(Metaspace):一种新的内存空间的诞生

   JDK8 HotSpot JVM 使用本地内存来存储类元数据信息并称之为:元空间(Metaspace);这与Oracle JRockit 和IBM J9很相似。如下图所示:

这将是一个好消息:意味着不会再有java.lang.OutOfMemoryError: PermGen问题,也不再需要你进行调优及监控内存空间的使用……但请等等,这么说还为时过早。在默认情况下,这些改变是透明的,接下来我们的展示将使你知道仍然要关注类元数据内存的占用。请一定要牢记,这个新特性也不能神奇地消除类和类加载器导致的内存泄漏。

java8中metaspace总结如下:

PermGen 空间的状况:

这部分内存空间将全部移除。JVM的参数:PermSize 和 MaxPermSize 会被忽略并给出警告(如果在启用时设置了这两个参数)。

Metaspace 内存分配模型:

大部分类元数据都在本地内存中分配。用于描述类元数据的“klasses”已经被移除。

Metaspace 容量:

默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小)。
    新参数(MaxMetaspaceSize)用于限制本地内存分配给类元数据的大小。如果没有指定这个参数,元空间会在运行时根据需要动态调整。

Metaspace 垃圾回收:

对于僵死的类及类加载器的垃圾回收将在元数据使用到“MaxMetaspaceSize”参数的设定值时进行。
    适时地监控和调整元空间对于减小垃圾回收频率和减少延时是很有必要的。持续的元空间垃圾回收说明,可能存在类、类加载器导致的内存泄漏或是大小设置不合适。

Java 堆内存的影响:

一些杂项数据已经移到Java堆空间中。升级到JDK8之后,会发现Java堆 空间有所增长。

Metaspace 监控:

元空间的使用情况可以从HotSpot1.8的详细GC日志输出中得到。
    Jstat 和 JVisualVM两个工具,在我们使用b75版本进行测试时,已经更新了,但是还是能看到老的PermGen空间的出现。
    前面已经从理论上充分说明,下面让我们通过“泄漏”程序进行新内存空间的观察……

PermGen vs. Metaspace 运行时比较

为了更好地理解Metaspace内存空间的运行时行为,
    将进行以下几种场景的测试:
    1. 使用JDK1.7运行Java程序,监控并耗尽默认设定的85MB大小的PermGen内存空间。
    2. 使用JDK1.8运行Java程序,监控新Metaspace内存空间的动态增长和垃圾回收过程。
    3. 使用JDK1.8运行Java程序,模拟耗尽通过“MaxMetaspaceSize”参数设定的128MB大小的Metaspace内存空间。

首先建立了一个模拟PermGen OOM的代码

<span style="color:#000000"><code>publicclassClassA {  publicvoidmethod(<span style="color:#009900 !important">String</span> name) {  <span style="color:#008800 !important">//</span> <span style="color:#000088 !important">do</span> nothing  }
}  </code></span>

上面是一个简单的ClassA,把他编译成class字节码放到D:/classes下面,测试代码中用URLClassLoader来加载此类型上面类编译成class

<span style="color:#000000"><code><span style="color:#880000 !important">/** * 模拟PermGen OOM *<span style="color:#4f4f4f !important"> @author</span> benhail */</span>
publicclassOOMTest {  publicstaticvoidmain(String[] args) {  <span style="color:#000088 !important">try</span>{  <span style="color:#880000 !important"><em>//准备url  </em></span>URL url = newFile(<span style="color:#009900 !important">"D:/classes"</span>).toURI().toURL();  URL[] urls = {url};  <span style="color:#880000 !important"><em>//获取有关类型加载的JMX接口  </em></span>ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();  <span style="color:#880000 !important"><em>//用于缓存类加载器  </em></span>List<ClassLoader> classLoaders = newArrayList<ClassLoader>();  <span style="color:#000088 !important">while</span>(<span style="color:#000088 !important">true</span>) {  <span style="color:#880000 !important"><em>//加载类型并缓存类加载器实例  </em></span>ClassLoader classLoader = newURLClassLoader(urls);  classLoaders.add(classLoader);  classLoader.loadClass(<span style="color:#009900 !important">"ClassA"</span>);  <span style="color:#880000 !important"><em>//显示数量信息(共加载过的类型数目,当前还有效的类型数目,已经被卸载的类型数目)  </em></span>System.out.println(<span style="color:#009900 !important">"total: "</span>+ loadingBean.getTotalLoadedClassCount());  System.out.println(<span style="color:#009900 !important">"active: "</span>+ loadingBean.getLoadedClassCount());  System.out.println(<span style="color:#009900 !important">"unloaded: "</span>+ loadingBean.getUnloadedClassCount());  }  } <span style="color:#000088 !important">catch</span>(Exception e) {  e.printStackTrace();  }  }
}  </code></span>

虚拟机器参数设置如下:-verbose -verbose:gc

设置-verbose参数是为了获取类型加载和卸载的信息

设置-verbose:gc是为了获取垃圾收集的相关信息

1.JDK 1.7 @64-bit – PermGen 耗尽测试

Java1.7的PermGen默认空间为85 MB(或者可以通过-XX:MaxPermSize=XXXm指定)

可以从上面的JVisualVM的截图看出:当加载超过6万个类之后,PermGen被耗尽。我们也能通过程序和GC的输出观察耗尽的过程。
程序输出(摘取了部分)

……
[Loaded ClassA from file:/D:/classes/]
total: 64887
active: 64887
unloaded: 0
[GC 245041K->213978K(536768K), 0.0597188 secs]
[Full GC 213978K->211425K(644992K), 0.6456638 secs]
[GC 211425K->211425K(656448K), 0.0086696 secs]
[Full GC 211425K->211411K(731008K), 0.6924754 secs]
[GC 211411K->211411K(726528K), 0.0088992 secs]
……………
java.lang.OutOfMemoryError: PermGen space

2.JDK 1.8 @64-bit – Metaspace大小动态调整测试

Java的Metaspace空间:不受限制 (默认)

从上面的截图可以看到,JVM Metaspace进行了动态扩展,本地内存的使用由20MB增长到646MB,以满足程序中不断增长的类数据内存占用需求。我们也能观察到JVM的垃圾 回收事件—试图销毁僵死的类或类加载器对象。但是,由于我们程序的泄漏,JVM别无选择只能动态扩展Metaspace内存空间。程序加载超过10万个 类,而没有出现OOM事件。

3.JDK 1.8 @64-bit – Metaspace 受限测试

Java的Metaspace空间:128MB(-XX:MaxMetaspaceSize=128m)

可以从上面的JVisualVM的截图看出:当加载超过2万个类之后,Metaspace被耗尽;与JDK1.7运行时非常相似。我们也能通过程序 和GC的输出观察耗尽的过程。另一个有趣的现象是,保留的原生内存占用量是设定的最大大小两倍之多。这可能表明,如果可能的话,可微调元空间容量大小策 略,来避免本地内存的浪费。

从Java程序的输出中看到如下异常。

[Loaded ClassA from file:/D:/classes/]
total: 21393
active: 21393
unloaded: 0
[GC (Metadata GC Threshold) 64306K->57010K(111616K), 0.0145502 secs]
[Full GC (Metadata GC Threshold) 57010K->56810K(122368K), 0.1068084 secs]
java.lang.OutOfMemoryError: Metaspace

在设置了MaxMetaspaceSize的情况下,该空间的内存仍然会耗尽,进而引发“java.lang.OutOfMemoryError: Metadata space”错误。因为类加载器的泄漏仍然存在,而通常Java又不希望无限制地消耗本机内存,因此设置一个类似于MaxMetaspaceSize的限制看起来也 是合理的。
总结

1.之前不管是不是需要,JVM都会吃掉那块空间……如果设置得太小,JVM会死掉;如果设置得太大,这块内存就被JVM浪费了。理论上说,现在你完全可以不关注这个,因为JVM会在运行时自动调校为“合适的大小”;
2.提高Full GC的性能,在Full GC期间,Metadata到Metadata pointers之间不需要扫描了,别小看这几纳秒时间;
3.隐患就是如果程序存在内存泄露,像OOMTest那样,不停的扩展metaspace的空间,会导致机器的内存不足,所以还是要有必要的调试和监控。

原文地址:(https://my.oschina.net/benhaile/blog/214159)

Java 8: 元空间(Metaspace)相关推荐

  1. java元空间扩容_调整元空间metaspace大小

    MaxMetaspaceSize和CompressedClassSpaceSize是控制元空间大小的旋钮 现在,这些参数可能有点混乱.首先,它们有两种,它们有着微妙的不同含义,它们相互影响. 所以让我 ...

  2. JVM原理系列--元空间(MetaSpace)与永久代(PermGen)的区别

    原文网址:JVM原理系列--元空间(MetaSpace)与永久代(PermGen)的区别_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍JVM中元空间(MetaSpace)与永久代(PermG ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新文章

  1. Oracle type (自定义类型的使用)
  2. PHP中spl_autoload_register函数的用法
  3. 我们的解决方案:日志系统
  4. 运用Kubernetes进行分布式负载测试
  5. 2 datax mysql 和 mysql之间相互导入
  6. python递归实现_Python-递归实现
  7. tensorflow GPU版本配置加速环境
  8. ObjectC----NSObject常用方法和OC反射机制
  9. udev介绍及两个小场景应用
  10. CAPL可以读写的几种文件
  11. lammps建模_LAMMPS之Moltemplate建模教程
  12. 试图通俗地讲一下庞加莱猜想是怎么回事
  13. jeecms mysql_JeeCms的环境搭建 | 学步园
  14. 10个低成本真实兼职,在家就能干的兼职有那些?
  15. (c#)小游戏 飞行棋
  16. 20221219 圣诞节,音乐圣诞树
  17. 计算机二级大题知识点汇总,计算机二级Excel考点与做题技巧汇总。
  18. “共识2018”北京区块链大会上BNET创始人刘建军发表了“通信网的未来”的重要演讲
  19. Learning English Lesson 2 - ( Accents )
  20. Sony ST27i 获取root权限

热门文章

  1. 功能需要富文本编译器图片不转base64,琢磨了一下,上代码
  2. 汇编中一些常用的debug命令
  3. 7-1 sdut-循环-7-统计正数和负数的个数(II) (10 分)
  4. Comparable的compareTo
  5. 百度地图配合java 代码制作地图
  6. 电脑怎么远程连接服务器?如何进行远程桌面连接?
  7. CCNA,CCNP,CCIE是什么?
  8. flash,php上传文件
  9. C语言及程序设计(公开课)主页
  10. 给研发培训资料两篇(架构设计大数据)