java.lang.OutOfMemoryError: Metaspace

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

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

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

  • 为什么会产生 java.lang.OutOfMemoryError: Java heap space 错误以及如何解决?
  • 详解 java.lang.OutOfMemoryError: GC overhead limit exceeded 错误!
  • 详解 java.lang.OutOfMemoryError: Permgen space 错误!

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以后,为了避免增加元数据空间的大小,空闲的类元数据的容量的最大比例,不够就会导致垃圾回收。

参考资料

  • https://plumbr.eu/outofmemoryerror/permgen-space
  • Metaspace in Java 8
  • What is the use of Metaspace in Java 8? – StackOverflow
  • About G1 Garbage Collector, Permanent Generation and Metaspace
  • JEP 122: Remove the Permanent Generation
  • PermGen elimination in JDK 8 – StackOverflow

java.lang.OutOfMemoryError: Metaspace

: » java.lang.OutOfMemoryError: Metaspace

原创文章,作者:254126420,如若转载,请注明出处:https://blog.ytso.com/tech/java/251920.html

(0)
上一篇 2022年5月3日 18:53
下一篇 2022年5月3日 18:57

相关推荐

发表回复

登录后才能评论