最近,我在推广我的个人微信公众号:。我发现当我认认真真写技术文章的时候,看的人并不多。当我写热点事件,或者科技新闻后发现阅读量又大幅的提升。于是,我就得出一个结论:技术越深的文章看的人越深;技术中等的次之;技术偏初级的看的人最多!这是为什么呢?原因很简单。这就和买房子一样啊,普通商品房买的人最多,复式套房要少一点,别墅再少一点。写的越深的文章,专家的文章就相当于别墅啊!你说是不是?
好了,言归正传,我们今天来说说 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。
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
原创文章,作者:254126420,如若转载,请注明出处:https://blog.ytso.com/tech/java/251920.html