28_Metaspace 内存溢出
884字约3分钟
2024-08-10
Metaspce 区的内存如何溢出的
JDK8
及以后,可以使用 -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=128M
设置 Metaspce
区域初始大小以及最大可分配大小
如果不指定元空间大小,默认情况下,元空间最大的大小是系统内存的大小,元空间一直扩大,虚拟机可能会消耗完所有的系统可用内存
Metaspce
区域满了就会触发 Full GC
,Full GC
会带着 Old GC
回收老年代,也会带着 Young GC
回收年轻代
当然,Full GC
的时候也会尝试回收 Metaspace
区域中的类
回收 Metaspace
区域中的类条件是相当苛刻的,包括不限于:这个类的加载器要先被回收、这个类对象实例都要被回收等
所以一旦 Metaspace
区域满了,未必能回收掉很多类,一旦回收不了多少类,JVM
还在不断加载类放到 Metaspace
中去
Metaspace
区域内存不够,就会发生内存溢出,说明 JVM
已经没办法继续运行下去了,系统也就直接奔溃了

Metaspace
这块区域很少发生内存溢出,一般有以下两个原因:
1、工程师不懂
JVM
运行原理,Metaspace
区域使用默认参数不设置大小,稍微大型一点的系统,自己有很多依赖,还依赖了很多外部jar
包的类,几十MB
的Metaspace
就很容易不够了2、系统中使用
cglib
之类的技术动态生成一些类,一旦代码中没有控制好,导致生成类过多将Metaspace
塞满了,引发内存溢出
模拟 Metaspace 内存溢出
设置 JVM
Metaspace
区内存,参数 -XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M
引入 cglib
的依赖,使用 CGLIB
来动态生成类,不用管具体代码,只需要知道不停的在往 Metaspace
区域增加类信息即可
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
CGLIB 动态生成类代码
/**
* @ClassName MetaspaceDemo
* @Desciption Metaspace 内存溢出模拟代码
* @Author MaRui
* @Date 2024/2/6 11:06
* @Version 1.0
*/
public class MetaspaceDemo {
public static void main(String[] args) {
long count = 0;
while (true) {
// 生成动态类,Animal 是生成类的父类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Animal.class);
enhancer.setUseCache(false);
// 调用子类 run 方法时拦截,打印一点日志,然后调用父类的 run 方法
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if ("run".equals(method.getName())) {
System.out.println("准备奔跑");
return methodProxy.invokeSuper(o, objects);
}
return methodProxy.invokeSuper(o, objects);
}
});
Animal car = (Animal) enhancer.create();
car.run();
System.out.println("目前已创建了 " + (++count) + " 个 Animal 类的子类了");
}
}
static class Animal {
public void run() {
System.out.println("开始奔跑......");
}
}
}
在代码中我们统计了创建了多少个类,日志如下,OutOfMemoryError
就是经典的内存溢出问题了,并且明确告诉你是 Metaspace
这块内存溢出了
而且可以看到,一旦内存溢出,本来运行的 JVM
进程会直接奔溃,程序直接退出
准备奔跑
开始奔跑......
目前已创建了 266 个 Animal 类的子类了
准备奔跑
开始奔跑......
目前已创建了 267 个 Animal 类的子类了
Caused by: java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
... 11 more
Metaspace 内存溢出解决
1、分析内存快照,找到是什么类占据了内存
2、一般来说是某次升级之后才出现问题,可以直接分析定位本次升级代码,可能存在问题的地方