使用LambdaMetaFactory导致元空间泄漏的原因及解决方法
LambdaMetafactory循环调用引发元空间泄漏问题
以下是我编写的代码:
public static void main(String[] args) throws IOException, NoSuchMethodException, IllegalAccessException, LambdaConversionException { MethodHandles.Lookup lookup = MethodHandles.lookup(); while (true) { Class<?> declaringClass = MyClass.class; Class<?> propertyType = List.class; String methodName = "getCustomerList"; LambdaMetafactory.metafactory(lookup, "apply", MethodType.methodType(Function.class), MethodType.methodType(Object.class, Object.class), lookup.findVirtual(declaringClass, methodName, MethodType.methodType(propertyType)), MethodType.methodType(propertyType, declaringClass)); } } public static final class MyClass { public List<String> getCustomerList() { return null; } }
这段代码会无限循环调用LambdaMetafactory.metafactory,既没有保存任何变量,也没有留存返回的CallSite对象,但很快就触发了如下错误:
Caused by: java.lang.OutOfMemoryError: Compressed class space
我已进行堆转储,正如预期,堆中未发现可能引发该问题的内容,Eclipse内存分析工具也未给出任何泄漏相关的建议。
VisualVM提供的已加载类图表显示类加载数量持续上升。
我的Java版本信息:
$ java -version openjdk version "17.0.7" 2023-04-18 OpenJDK Runtime Environment Temurin-17.0.7+7 (build 17.0.7+7) OpenJDK 64-Bit Server VM Temurin-17.0.7+7 (build 17.0.7+7, mixed mode, sharing)
疑问
- 这种元空间泄漏是如何发生的?
- 我该如何预防?
补充测试结果
根据评论建议,在循环中添加System.gc()后,问题恶化速度显著减慢:类仍持续加载且不会被卸载,但元空间增长速度大幅降低——此前几秒就会出现OOM,现在运行10分钟后,元空间占用未超过50MB。不过元空间仍会无限增长,最终仍会触发OOM。
我还发现一个更奇怪的现象:为什么调用System.gc()能大幅减缓泄漏速度,但正常应用运行中偶尔触发Full GC,却似乎对泄漏影响不大?
内容的提问来源于stack exchange,提问作者Lukáš Petrovický
相关产品推荐
相关产品推荐

