Spring Boot GraalVM Native镜像约50MB是否正常?有何优化方案?
问题
我尝试使用GraalVM将一个仅包含主文件的空Spring Boot应用编译为Native镜像,执行gradle nativeCompile后生成的镜像大小约为50MB。查看构建日志(如下所示),请问该大小是否符合预期?是否存在遗漏的优化手段?
======================================================================================================================== [1/8] Initializing... (4.9s @ 0.24GB) Java version: 17.0.7+8-LTS, vendor version: Oracle GraalVM 17.0.7+8.1 Graal compiler: optimization level: 2, target machine: x86-64-v3, PGO: ML-inferred C compiler: cl.exe (microsoft, x64, 19.36.32534) Garbage collector: Serial GC (max heap size: 80% of RAM) 1 user-specific feature(s) - org.springframework.aot.nativex.feature.PreComputeFieldFeature Field org.apache.commons.logging.LogAdapter#log4jSpiPresent set to true at build time Field org.apache.commons.logging.LogAdapter#log4jSlf4jProviderPresent set to true at build time Field org.apache.commons.logging.LogAdapter#slf4jSpiPresent set to true at build time Field org.apache.commons.logging.LogAdapter#slf4jApiPresent set to true at build time Field org.springframework.cglib.core.AbstractClassGenerator#imageCode set to true at build time Field org.springframework.boot.logging.java.JavaLoggingSystem$Factory#PRESENT set to true at build time Field org.springframework.core.NativeDetector#imageCode set to true at build time Field org.springframework.boot.logging.log4j2.Log4J2LoggingSystem$Factory#PRESENT set to false at build time Field org.springframework.boot.logging.logback.LogbackLoggingSystem$Factory#PRESENT set to true at build time Field org.springframework.core.KotlinDetector#kotlinPresent set to true at build time Field org.springframework.core.KotlinDetector#kotlinReflectPresent set to true at build time Field org.springframework.format.support.DefaultFormattingConversionService#jsr354Present set to false at build time Field org.springframework.boot.logging.logback.LogbackLoggingSystemProperties#JBOSS_LOGGING_PRESENT set to false at build time Field org.springframework.context.event.ApplicationListenerMethodAdapter#reactiveStreamsPresent set to false at build time [2/8] Performing analysis... [*****] (12.9s @ 1.21GB) 11,346 (88.27%) of 12,854 types reachable 17,177 (67.40%) of 25,485 fields reachable 58,937 (61.80%) of 95,367 methods reachable 3,583 types, 134 fields, and 1,826 methods registered for reflection 78 types, 74 fields, and 62 methods registered for JNI access 5 native libraries: crypt32, ncrypt, psapi, version, winhttp [3/8] Building universe... (1.9s @ 1.87GB) [4/8] Parsing methods... [**] (4.4s @ 1.35GB) [5/8] Inlining methods... [***] (0.5s @ 2.52GB) [6/8] Compiling methods... [*****] (28.5s @ 4.55GB) [7/8] Layouting methods... [**] (3.2s @ 2.09GB) [8/8] Creating image... [**] (3.2s @ 2.62GB) 32.11MB (59.34%) for code area: 31,614 compilation units 21.57MB (39.87%) for image heap: 311,575 objects and 33 resources 440.91kB ( 0.80%) for other data 54.12MB in total ------------------------------------------------------------------------------------------------------------------------ Top 10 origins of code area: Top 10 object types in image heap: 10.81MB java.base 6.62MB byte[] for code metadata 5.09MB kotlin-reflect-1.8.21.jar 3.15MB byte[] for java.lang.String 3.44MB java.xml 2.24MB java.lang.String 3.25MB svm.jar (Native Image) 2.02MB java.lang.Class 2.05MB spring-core-6.0.9.jar 1.88MB byte[] for general heap data 1.45MB spring-boot-3.1.0.jar 673.03kB byte[] for reflection metadata 857.06kB spring-beans-6.0.9.jar 531.84kB com.oracle.svm.core.hub.DynamicHubCompanion 754.30kB logback-core-1.4.7.jar 487.22kB java.util.HashMap$Node 623.80kB spring-expression-6.0.9.jar 397.81kB java.util.concurrent.ConcurrentHashMap$Node 391.42kB kotlin-stdlib-1.8.21.jar 320.75kB c.o.svm.core.hub.DynamicHub$ReflectionMetadata 3.23MB for 46 more packages 2.94MB for 2231 more object types
回答
是否符合预期
这个54MB左右的镜像大小属于正常现象。从日志的资源占比可以看出:
- Java基础库(java.base)占10.81MB,这是Native镜像的基础开销,无法完全移除
- Kotlin相关依赖(kotlin-reflect、kotlin-stdlib)合计占近5.5MB,若为纯Java开发,这部分属于可移除的额外开销
- Spring核心组件(spring-core、spring-boot等)合计约4.3MB,是Spring Boot Native的必要基础依赖
- 日志框架(logback)等组件也占据了部分体积
空Spring Boot Native镜像的常规大小区间在40-60MB,你的结果完全处于合理范围。
可尝试的优化手段
- 移除Kotlin相关依赖:如果应用是纯Java开发,检查
build.gradle中是否引入了Kotlin插件或kotlin-reflect等依赖,移除后可减少约5MB镜像体积 - 替换轻量日志框架:将logback替换为
slf4j-simple,能缩减约700KB的日志组件开销 - 启用激进优化级别:构建时添加参数
-PnativeOptimizationLevel=3,对应GraalVM的O3优化级别,可进一步压缩代码体积,但会增加构建时间 - 切换Epsilon GC:若应用为无状态短生命周期服务,可通过
--gc=epsilon参数替换默认的Serial GC,减少GC相关代码开销 - 裁剪Java基础库:通过Gradle插件配置
--initialize-at-build-time,手动指定无需运行时初始化的类;若应用不使用XML解析,可添加--exclude-config=java.xml移除该模块,减少基础库体积 - 系统级压缩镜像:构建完成后使用
upx等工具压缩镜像(注意:该操作可能影响启动速度,需测试验证)
内容的提问来源于stack exchange,提问作者Mehdi
相关产品推荐
相关产品推荐

