quarkus-graalvm 可以救 Java native 一命

110 天前
 karottc

前文是这个项目:果然吃内存,一个简单的 Java 程序就占用了 250M 内存

用 quarkus + graalvm 重新了这个项目(顺便学习了下 quarkus, 获益匪浅),功能逻辑全部保持了一致,只是组件根据框架进行了平移(比如 okhttp -> rest-client ).

程序的功能为:

这就是这个程序的所有功能,这版用到的组件和框架为 quarkus + gson + mybaits + jdbc + quarkus-rest-clint(发送网络请求) + jboss(quarkus 的默认日志)

编译环境:linux-x86-64, graalvm-21.(社区版),编译之后的二进制大小是 100M 。编译耗时大概十几分钟。 openjdk version "21.0.2" 2024-01-16 OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30) OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing)

启动之后,占用 90M 内存,然后我调用了好几次 rest 请求,内存涨到了 120M ,过了一天程序稳定运行之后内存占用在 40-50M 左右。

虽然和我预期的 20M 内存有差距,但是已经比较满意了。虽然量起来了,内存占用一样会升高,但是没量了会把内存还给操作系统。quarkus 的启动速度确实快,毫秒级。

这次项目的意义,在于让我学会了 quarkus,(除了上面的项目,我还用 quarkus-picocli 写了个命令行工具,也很不错) 不愧是自古评论出人才。


此外,我用 python 实现了上面项目的核心部分,稳定之后内存占用 20M 。


最后,吹一下 quarkus, 在 native 这块很强,和 graalvm 的集成度非常高,比如反射问题单纯用 graalvm 需要繁琐的配置文件,在 quarkus 里面用一个注解就行了,方便很多。

缺点就是编译略慢,而且需要高配机器,配置越高,编译越快。


单纯的 graalvm 还是非常不行, 2024 年,graalvm native image 仍较为勉强 这个帖子也说了,但是和 quarkus 搭配一下就很不错了。

5256 次点击
所在节点    Java
24 条回复
GogoGo666
110 天前
这种情况还是换 go 吧,不管是编译后的二进制大小,编译耗时,内存占用,都比 java 强太多了
yazinnnn0
110 天前
自己玩没问题, 在大规模生产环境中使用会变得不幸, 除非你在红帽工作, 身边都是 quarkus 贡献者
karottc
110 天前
@GogoGo666 认真学了一段时间,然后没有工作环境持续,并且也不是很喜欢,然后就放弃了。
wssy001
110 天前
无论是 springboot 还是 Quarkus 在改造成 Native Image 项目中 都会面临重构轮子的窘境
JVM 环境中,开发者 Google 到一个好轮子可以拿来直接用,而在 Native Image 中,开发者不得不考虑该怎么用原生的方式“曲线救国”
这是我这几年玩 GraalVM Native Image 的心得,最后得出一个结论:鉴于目前 Native Image 的生态,我觉得把项目用 go 重构的代价要比改成 Native Image 低不少(时间+精力方面)
feiyan35488
110 天前
在意内存和制品大小的话,还考虑下 go 、rust 吧
缺硬件资源的企业不会用 java 的
zhaojun1998
110 天前
Spring Boot 改造现在已经还不错了,花了一周左右时间把一个 Spring Boot 2.6 (JDK1.8) 的项目,升级到 Spring Boot 3.3.0(JDK 21) Native 不算太麻烦,简单点说就是标记下哪些类用到了反射,要做 native 处理,如果库本身做了那你就不用做,如果没做,你自己添加到配置文件也行。

编译速度也做过测试,内存占的比重大于 CPU 性能,编译时可用内存最好 16+

也不必谈 Java 色变,我觉得在这方面的努力这几年还是挺多的,估计过几年打包 native 就跟打包一个 jar 方便了。

不过缺点也有:编译速度慢,编译占用资源多,不支持交叉编译,社区不看好导致很多库不愿兼容 (我当时找兼容 flyway 时费了老大劲,后来发现还是 springboot 的工程师去兼容的,他们提交给 flyway 官方也不愿理睬)
sunny352787
110 天前
用 go 写了个模拟,获取 baidu 首页然后插入 mongo ( upsert ),内存占用 2.9M ,rust 会不会是 k 级别?
karottc
110 天前
@zhaojun1998 springboot 上,mybatis 加了配置文件也不行
Goooooos
110 天前
正常程序员都会多种语言,不同场景选自己熟悉和合适的语言即可
1. 日常业务开发,我会用 Java
2. 导数据、数据分析,我用 python
3. 小组件,用 go
4. 前端,用 js 或 ts
qq135449773
110 天前
其实有的时候解决 Java 的这种体积或者资源占用问题,最好的办法就是不用 Java
javak
110 天前
我也不喜欢 go ,推荐学习下 rust ,大家都说好。我也觉得好(虽然我没用过)
sagaxu
110 天前
@yazinnnn0 quarkus 用户基数太少了,我直接用的 vertx ,小版本常有大改动,遇到过不少问题,比如

redis client 超过 20 亿个请求之后 index 溢出;
http server 某个版本 pause request 但 resume 处理不当,导致无法正常处理某些 HTTP 请求;
redis 连接池连接泄漏;
Templatehandler 找不到子目录下的模板;

这 4 个其中 3 个我提了 issue ,好在都很快解决了。

vertx 这玩意儿,不像 spring 家族那样可以无脑使用,但是用顺手了却非常舒适,即便出了问题,也很容易定位和解决,毕竟比 spring 全家桶简单太多了。

=====================================================================================

这类小工具,用 Go 写也很舒服,graalvm build 几次的时间都够我用 Go 写完上线了


@zhaojun1998 我觉得 graalvm 的 native 要达到可用,还需要从预编译入手,发布 jar 的同时发布预编译文件,用户 build 时从预编译文件中提取组合,而不是把编译工作全部放在使用者的机器上做。解决了生态和资源消耗问题,可用性就起来了。这需要很长时间和很大存储空间,也不一定有足够多的资源投入。
kneo
110 天前
你喜欢就好。
chendy
110 天前
羡慕楼主玩这么花还没人管
CodeCodeStudy
110 天前
我电脑 i7-6700 ,16G 内存,编译 hello,world 需要 34 秒,编译后的可执行文件是 6M 。

编译很久,连 graalvm 官方都出教程,编译完后怎么系统通知开发者

https://www.graalvm.org/latest/reference-manual/native-image/overview/Build-Overview/#getting-notified-when-the-build-process-is-done
CodeCodeStudy
110 天前
我电脑 i7-6700 ,16G 内存,编译 hello,world 需要 34 秒,编译后的可执行文件是 6M 。

编译很久,连 graalvm 官方都出教程,编译完后怎么系统通知开发者

https://www.graalvm.org/latest/reference-manual/native-image/overview/Build-Overview/#getting-notified-when-the-build-process-is-done
luciankaltz
110 天前
我们之前某个小组件用 quarkus + native image 试了一下,结果发现有些莫名其妙的坑,比如上面说到的反射之类的。如果需要手动一个一个标注也太麻烦了(指没必要

说起来 quarkus 坑也很多就是了,还是不如 spring (

一定要扣这些资源,不如直接用 go 重写就是了(
INCerry
110 天前
可以直接用.NET 走 NativeAOT ,我之前搞个 ASP.NET Core 项目启动内存占用 15MB 不到,压测以后不到 50MB ,还可以用更轻量的 http 框架,C#语法和 Java 差不多,半天就能上手。
artiga033
109 天前
@INCerry .NET AOT 这么多年了其实也就刚到勉强能用的阶段,性能折扣且不论,好多库还是不兼容 AOT 的,ASP.NET Core 还好,像桌面开发那边一大堆库都不兼容,因为大量使用反射,而且不说外部库,就是自己写代码,写 Source Generator 也比写反射折磨多了,论元编程能力个人感觉没有语言比得过 rust 。

Java 的 AOT 方案我不了解,不过感觉.NET 和 Java 这种感觉与其折腾预编译,不如考虑像 go 那样缩小 runtime 体积,但还是带一个 runtime 来做 gc 之类的。至少.NET AOT 直接就损失了大部分的运行时动态操作能力,而且 JIT 会对热点代码做高度优化,同一个函数调用次数越多性能越好,极有可能最终实际性能比 AOT 还高。
janus77
109 天前
作为对比,你提到的 python 项目编译和启动速度如何

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1057699

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX