升级GraalVM至22.3.2后Micronaut应用原生镜像构建失败
环境与问题说明
构建配置
使用native-image命令编译Micronaut应用:
native-image -cp build/libs/*-all.jar
对应的native-image.properties配置:
Args = -H:ResourceConfigurationFiles=build/graal/resource-config.json,build/native/generated/generateResourcesConfigFile/resource-config.json \ -H:ReflectionConfigurationFiles=build/graal/reflect-config.json,build/resources/main/graal/reflect-config.json \ -H:JNIConfigurationFiles=build/graal/jni-config.json \ -H:DynamicProxyConfigurationFiles=build/graal/proxy-config.json \ -H:PredefinedClassesConfigurationFiles=build/graal/predefined-classes-config.json \ -H:Name=micronautgraalapp \ --no-fallback \ --report-unsupported-elements-at-runtime \ --initialize-at-build-time=sun.instrument.InstrumentationImpl \ --install-exit-handlers \ -H:EnableURLProtocols=http,https \ -H:+ReportExceptionStackTraces \ -H:+StaticExecutableWithDynamicLibC \ -J-Xmx3072m \ -J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk=ALL-UNNAMED \ -H:Class=io.github.devatherock.ldapsearch.Application
构建流程
通过make fast-build docker-build执行:先运行测试生成反射配置,再在Docker容器内构建原生镜像。
问题现象
GraalVM 22.1.0版本下构建成功,但升级到22.3.2后失败,抛出异常:
#10 84.42 Error: Unsupported features in 4 methods #10 84.42 Detailed message: #10 84.42 Error: Detected a ZipFile object in the image heap. A ZipFile object contains pointers to unmanaged C memory and file descriptors, and these resources are no longer available at image runtime. To see how this object got instantiated use --trace-object-instantiation=java.util.jar.JarFile. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point. #10 84.42 Trace: Object was reached by #10 84.42 reading field jdk.internal.module.ModuleReferences$JarModuleReader.jf of constant #10 84.42 jdk.internal.module.ModuleReferences$JarModuleReader@7205edd8: jdk.internal.module.ModuleReferences$JarModuleReader@7205edd8 #10 84.42 reading field java.util.concurrent.ConcurrentHashMap$Node.val of constant #10 84.42 java.util.concurrent.ConcurrentHashMap$Node@4d58ca3f: [module org.graalvm.nativeimage.builder, location=file:///usr/lib64/graalvm/graa... #10 84.42 indexing into array java.util.concurrent.ConcurrentHashMap$Node[]@639968a3: [Ljava.util.concurrent.ConcurrentHashMap$Node;@639968a3 #10 84.42 reading field java.util.concurrent.ConcurrentHashMap.table of constant #10 84.42 java.util.concurrent.ConcurrentHashMap@60bb74c6: {[module jdk.internal.ed, location=jrt:/jdk.internal.ed]=jdk.internal.module.Sys... #10 84.42 reading field jdk.internal.loader.BuiltinClassLoader.moduleToReader of constant #10 84.42 jdk.internal.loader.ClassLoaders$AppClassLoader@2cfb4a64: jdk.internal.loader.ClassLoaders$AppClassLoader@2cfb4a64 #10 84.42 reading static field java.lang.ClassLoader.scl
尝试添加--initialize-at-run-time=java.util.jar.JarFile,java.util.zip.ZipFile未解决,反而触发"类已初始化"错误。
解决方案
1. 调整ClassLoader相关类的初始化时机
错误追踪显示,问题根源是应用类加载器(AppClassLoader)的静态字段持有了包含ZipFile的模块读取器。需将相关ClassLoader类设置为运行时初始化,在native-image.properties的Args中添加:
--initialize-at-run-time=jdk.internal.loader.ClassLoaders$AppClassLoader,jdk.internal.loader.BuiltinClassLoader
避免直接设置JarFile/ZipFile为运行时初始化,因为它们可能已被构建阶段初始化的类加载,导致冲突。
2. 追踪JarFile实例化源头
添加--trace-object-instantiation=java.util.jar.JarFile参数重新构建,定位哪个类在构建阶段触发了JarFile的创建,针对性调整该类的初始化时机。
3. 升级Micronaut版本
Micronaut会随版本更新优化对新GraalVM版本的兼容性,升级到适配GraalVM 22.3.x的Micronaut版本,可能已修复此类初始化时机问题。
4. 检查构建时初始化参数
当前配置中--initialize-at-build-time=sun.instrument.InstrumentationImpl若并非必需,可尝试移除,避免不必要的提前初始化触发连锁问题。
内容的提问来源于stack exchange,提问作者devatherock

