java 打 graalvm native 包
最近v2ex上java的热门话题是java太占内存了balabala,就挺感慨,java当年从一个在家电之类的小型嵌入设备语言,发展到今天的“企业级”应用语言,确实变成吃内存大户了,当然如今的环境下,多个百十来M的内存,和jvm、spring全家桶带给我们的开发便利与稳定性相比,就不值一提了。几篇帖子的测试表明,java裸跑一个hello world都要消耗30m的内存,在一些极端场景(比如跑在内存极其苛刻的物联网设备上),还是有些无法接受。
所以,本文介绍了基于graalvm打native包的方式,为您提供一种在需要轻量级环境下运行java程序的选择。
native优缺点
native包的优点:启动快、占用内存少;不用java环境(windows下直接双击exe运行,linux下敲./xxx名运行)
native包的缺点:没有JIT的优化,性能通常会差一些;不能一处编译到处运行了,需要打多个平台的native包;反射等代码处理起来比较麻烦
环境准备
windows平台
1)安装graalvm jdk
https://www.graalvm.org/downloads/# 下载windows版的graalvm jdk,
然后解压,像普通jdk一样配置环境变量:
这里把GRAALVM_HOME也配上,不然后面用命令行编译的话会报找不到GRAALVM_HOME
2)安装VisualStudio
要编译成.exe文件,必须做这一步,否则后面会报错"native-image-xxx.args xxx returned non-zero result"
去这个地址下载
然后安装时勾选“使用C++的桌面开发”,子选项里把“MsVC v143 - vS 2022C++ x64/x86生成工...”、“Windows 10 SDK (10.0.20348.0)”这俩勾上,如果你是win11就勾11的。
然后一路下一步,安装完后重启电脑,我们的环境就准备完成了。
linux平台
linux下就简单多了, https://www.graalvm.org/downloads/# 下载linux版的graalvm jdk,解压后 vi ~/.bashrc添加如下环境变量
编写一个helloworld
新建一个maven项目,修改下pom文件:
再添加一个测试类
好了,idea里maven reload一下,就可以点这两个按钮来分别编译jar包或native包了
也可以直接运行如下命令编译jar包或native包
两个命令没有前后关系,可以独立运行
打包完成后,target目录下得到如下产物:
native只有6m的可独立运行文件,跑起来占用大约6-8m,效果还是比较好的。
但是运行耗时会稍微变长一点:
如果需要在本地包运行时添加jvm参数,或者传参到main方法的args中,可以这样:
解决反射
我们把demo改一下,用反射来加载一个方法并调用,按上面的配置直接打包并执行 nativedemo.exe t2.Service1 的话会报错 ClassNotFoundException:
此时,我们需要新建一个文件src/main/resources/META-INF/native-image/reflect-config.json,并在其中指明我们需要反射操作的类:
整体文件结构如下:
再次编译(有时候需要先clean、package一下),运行nativedemo.exe t2.Service1 就能成功反射到了。
实际应用中,如果手工把需要反射的类都罗列一遍也太辛苦了,这是可以先以如下命令启动jar包:
java -agentlib:native-image-agent=config-output-dir=META-INF/native-image -jar xx.jar
然后设法让jar包运行覆盖到所需的业务逻辑代码,此时META-INF/native-image下就生成了所需json了
另,获取native包所在路径时,用ClassLoader行不通,可以用如下代码:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律