java.lang.OutOfMemoryError: Metaspace

JAVA herman 977浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

最近,我在推广我的个人微信公众号:业余草。我发现当我认认真真写技术文章的时候,看的人并不多。当我写热点事件,或者科技新闻后发现阅读量又大幅的提升。于是,我就得出一个结论:技术越深的文章看的人越深;技术中等的次之;技术偏初级的看的人最多!这是为什么呢?原因很简单。这就和买房子一样啊,普通商品房买的人最多,复式套房要少一点,别墅再少一点。写的越深的文章,专家的文章就相当于别墅啊!你说是不是?

好了,言归正传,我们今天来说说 java.lang.OutOfMemoryError: Metaspace 错误。

没看过前面文章的网友,可以看看我的深入理解 JVM OutOfMemoryError 系列文章:

Metaspace 这个东西是在 JDK8 后才有的。Java 8 彻底将永久代 (PermGen) 移除出了 HotSpot JVM,将其原有的数据迁移至 Java Heap 或 Metaspace。

PermGen 永久代中用于存放类和方法的元数据以及常量池,比如 Class 和 Method 等。永久代是有大小限制的,因此如果加载的类太多,很有可能导致永久代内存溢出,即万恶的 java.lang.OutOfMemoryError: PermGen ,为此我们不得不对虚拟机做调优。

所以 java 8 中 PermGen 最终被移除,方法区移至 Metaspace,字符串常量移至 Java Heap。

java8 中堆内存划分

Metaspace 的大小值, 由 -Xmx 和 -XX:MaxMetaspaceSize 等 JVM 启动参数指定. 如果没有明确指定, 则根据平台类型(OS 版本 + JVM 版本)和物理内存的大小来确定。

java.lang.OutOfMemoryError: Metaspace 错误所表达的信息就是元数据区(Metaspace) 已被用满。

由于方法区被移至 Metaspace,所以 Metaspace 的使用量与 JVM 加载到内存中的 class 数量/大小有关。可以明确的说 java.lang.OutOfMemoryError: Metaspace 错误的主要原因, 是加载到内存中的 class 数量太多或者体积太大。

下面我们再使用 javassist 工具加载一些 class 到 Metaspace 中,演示一个 java.lang.OutOfMemoryError: Metaspace 错误!

public class Metaspace {
  static javassist.ClassPool cp = javassist.ClassPool.getDefault();
  // 业余草:www.xttblog.com
  public static void main(String[] args) throws Exception{
    for (int i = 0; ; i++) { 
      Class c = cp.makeClass("com.xttblog.demo.Generated" + i).toClass();
    }
  }
}

执行这段代码, 随着生成的 class 越来越多, 最后将会占满 Metaspace 空间, 抛出 java.lang.OutOfMemoryError: Metaspace. 在 Mac OS X上, Java 1.8.0_05 环境下, 如果设置了启动参数 -XX:MaxMetaspaceSize=64m, 大约加载 70000 个 class 后 JVM 就会挂掉。

如果抛出与 Metaspace 有关的 OutOfMemoryError,第一解决方案是增加 Metaspace 的大小。

-XX:MaxMetaspaceSize=512m

有一种看起来很简单的方案,是直接去掉 Metaspace 的大小限制。但需要注意,不限制 Metaspace 内存的大小,假若物理内存不足,有可能会引起内存交换(swapping),严重拖累系统性能。 此外,还可能造成 native 内存分配失败等问题。

除此之外,VisualVM、jstat、jstack 都可以监测 Metaspace 的动态。

与 Metaspace 相关的还有 4 新增的 JVM 参数:

  • -XX:MetaspaceSize 是分配给类元数据空间(以字节计)的初始大小(Oracle逻辑存储上的初始高水位,the initial high-water-mark ),此值为估计值。MetaspaceSize的值设置的过大会延长垃圾回收时间。垃圾回收过后,引起下一次垃圾回收的类元数据空间的大小可能会变大。
  • -XX:MaxMetaspaceSize 是分配给类元数据空间的最大值,超过此值就会触发Full GC,此值默认没有限制,但应取决于系统内存的大小。JVM会动态地改变此值。
  • -XX:MinMetaspaceFreeRatio 表示一次GC以后,为了避免增加元数据空间的大小,空闲的类元数据的容量的最小比例,不够就会导致垃圾回收。
  • -XX:MaxMetaspaceFreeRatio 表示一次GC以后,为了避免增加元数据空间的大小,空闲的类元数据的容量的最大比例,不够就会导致垃圾回收。

参考资料

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » java.lang.OutOfMemoryError: Metaspace