ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JDK16 ARM版安装实战:AArch64与armhf架构选择及排坑指南

JDK16 ARM版安装实战:AArch64与armhf架构选择及排坑指南 简介面向 ARM64 架构 Linux 平台的 JDK16 开发套件对应官方 OpenJDK16U-jdk_aarch64_linux_hotspot_16.0.1_9.tar.gz适配树莓派、鲲鹏等 aarch64 服务器满足在 ARM 环境运行 Java 16 程序或搭建我的世界 1.17.1 服务端的开发与部署需求。整个 gz 压缩包共 450 个文件大小约 193.66MB核心组件包括 71 个 jmod 模块描述、70 个 license 许可、37 个 so 本地动态库以及 java、javac、jlink、jpackage、jshell 等常用命令辅以 h 头文件、properties 配置、security/policy 安全策略和 31 个 md 文档目录结构标准完整。已有 1665 人浏览学习此资源。下载后配置 JAVA_HOME 与 PATH 即可直接使用免去自行编译 OpenJDK 的流程适合在低功耗 ARM 设备上快速部署 Java 服务或 MC 服务端同时利用 jlink 可以裁剪出更小的自定义运行时为后续打包发布提供便利。 2021年3月发布的Java 16在Java版本序列里算是个有点“过渡”的位置它既不像Java 11那样被当成长期支持版本也不像后面的Java 17那样一出来就直接面向生产环境。但它在ARM平台上的意义反而比很多人想象中重要。那段时间我恰好在一台飞腾处理器的工控机上部署Java服务随手从网上找了一个JDK包结果不是Exec format error就是glibc版本不匹配折腾到半夜才弄明白问题不是出在JDK本身而是ARM平台的架构区分远比我想的细。这篇博文就围绕JDK 16 ARM版把下载、安装、验证和排坑的全过程都梳理一遍适合嵌入式开发者、ARM服务器运维人员以及想在树莓派或国产ARM设备上跑Java服务的朋友参考。1. 为什么ARM机器上的JDK不能随便下载1.1 ARM和x86_64从底层就是两种生物先别急着下载下载之前需要先弄清楚目标机器的CPU指令集。ARM和x86_64的差异可以拿柴油发动机和汽油发动机来类比虽然都是驱动汽车但内部工作原理完全不同油加错了车就趴窝。JDK也是这样官网上下载的linux-x64后缀安装包生成的是x86_64指令你把它放到ARM处理器上执行系统根本不认识这些指令直接抛出cannot execute binary file。很多第一次在ARM设备上部署Java的人都会栽在这个地方。因为Java号称“一次编写到处运行”但这个“到处”的前提是安装对应平台的JVM。Java本身的跨平台是靠不同平台的JVM实现来完成的而不是说同一个JDK二进制能通吃所有CPU。所以拿到ARM设备后第一件事就是确认CPU架构这决定了你接下来搜索和下载什么后缀的包。1.2 JDK 16在ARM平台上的特殊位置Java 16是2021年3月16日发布的正式版本它不属于LTS长期支持版本下一个LTS是Java 17。那为什么单独聊JDK 16的ARM版因为从Oracle JDK 9开始官方对ARM的支持策略有过一次非常明显的变化AArch64也就是64位ARM拿到了官方支持但32位ARM的直接支持被逐步弱化。到了Java 16Oracle官方发布包里只有linux-aarch64压根没有linux-arm32这个版本。如果你手里的设备是树莓派3B这类32位ARM板子那官方JDK 16基本不用考虑了只能去找第三方发行版或者自行编译。很多人在这一步容易卡住因为他们默认“官网有的下载ARM应该都支持”实际上官方支持的ARM范围已经缩小到AArch64这一条线。1.3 网上那些“ARM版JDK”到底怎么区分我在搜索资料时看到有一条热搜词是“jdk arm 和aarch64选哪个”这问题其实已经说到点子上了。ARM平台内部分成好几个子类最常见的是AArch64也叫ARM64、arm64是64位ARM指令集目前几乎所有新出的ARM处理器都是它比如飞腾、鲲鹏、树莓派4及以后的型号。armhf32位ARM硬浮点常见于比较老的嵌入式板卡和部分入门级树莓派镜像。armel32位ARM软浮点性能弱现在基本很少碰到。选择逻辑很简单64位ARM处理器选aarch64版本只有老旧的32位设备才需要去找armhf版。而且即便都是ARM32位和64位也是完全不同的二进制格式不能混用。我这里建议优先选择aarch64因为现代JDK在64位上的性能、内存寻址能力和默认GC表现都要好不少。另外国内一些Linux发行版会在自己的软件源里维护JDK比如麒麟系统里直接apt install openjdk-16-jre就能装上。这类版本通常更贴近系统本身的库环境安装确实省心但版本可能滞后而且不一定叫“JDK 16”更多时候是跟着发行版自己的节奏走。2. JDK16 ARM版完整安装流程2.1 安装前先确认目标机架构别急着下载我记得自己第一次在ARM服务器上部署时没有认真确认架构下载了一个“看上去通用”的JDK最后白白浪费了一个晚上。所以现在不管多急我都会先执行这三条命令uname -m dpkg --print-architecture lscpu | grep Architectureuname -m在64位ARM Linux上通常输出aarch64在32位ARM上通常输出armv7l。dpkg --print-architecture在Debian系系统上会输出arm64或armhf。lscpu里的Architecture字段可以辅助确认。如果uname -m显示aarch64但dpkg显示armhf说明系统是64位内核配了32位用户态这种情况要按dpkg的输出去选版本。这一步别偷懒。拿不准的时候可以在终端里执行file /bin/ls看返回里是AArch64还是ARM那是更直观的判断方式。确认清楚了再决定下载哪个包能省掉后面大量排错时间。2.2 下载渠道与版本选择JDK 16 ARM版的下载渠道我实际用得比较多的是OpenJDK官方archive页面。Java 16的最终更新版本是16.0.2建议直接下载这个版本不要用EA早期体验版。下载时认准文件名的linux-aarch64后缀类似jdk-16.0.2_linux-aarch64_bin.tar.gz。如果你所在的环境不方便访问国外站点可以先在内网一台可联网的机器上下载再通过内网传输工具拷过去。这里只讨论正常的软件获取方式不涉及任何额外的代理操作目的就是拿到一个合适的安装包。还有一类渠道是Azul Zulu、Adoptium Temurin这些第三方发行版。它们除了提供aarch64还保留了armhf的包对老设备很友好。页面筛选条件也比较直观可以按操作系统、架构、版本逐项选。个人经验能上官方JDK就上官方需要32位ARM或者特殊商业支持的时候再看Zulu和Temurin。2.3 解压安装与环境变量配置JDK本质上是绿色软件解压即用不需要像Windows那样跑安装向导。把下载好的tar.gz放到/opt目录下cd /opt sudo tar -zxvf jdk-16.0.2_linux-aarch64_bin.tar.gz解压完成后会生成/opt/jdk-16.0.2目录。接下来配置环境变量。我喜欢在/etc/profile.d/下面新建一个jdk.sh文件这样做的好处是所有用户登录时都会自动加载不用单独改每个用户自己的.bashrc。sudo vi /etc/profile.d/jdk.sh写入以下内容export JAVA_HOME/opt/jdk-16.0.2 export PATH$JAVA_HOME/bin:$PATH保存后执行source /etc/profile.d/jdk.sh java -version如果输出OpenJDK 64-Bit Server VM的版本信息就说明安装成功了。需要注意的是有些系统可能已经有系统自带的Java在配置PATH时JAVA_HOME/bin要放在前面这样最终执行的是我们新装的JDK。2.4 离线环境怎么分发安装包实际项目里经常会遇到目标机完全不能访问外网的场景比如闭网的工控系统。这种时候离线安装JDK反而是最方便的比在线装省事得多。因为JDK不依赖复杂的安装程序只要把tar.gz文件拷贝到目标机解压配置就行。分发方式我常用的有两种第一种是U盘拷贝适合单台或者少量设备第二种是搭建一个内网HTTP服务把安装包放上去目标机用wget或者curl拉取。不管哪种方式复制完先执行md5sum或sha256sum校验一下包完整性避免传输过程中文件损坏。JDK包损坏后会出现解压报错或者启动时缺少文件的诡异问题校验能提前发现。另外离线环境下一定要预先确认目标机的glibc版本。JDK 16本身对系统的依赖不算低如果目标机系统太老后面会遇到GLIBC版本不足的报错这个我在第4章专门展开讲。3. 新装好的JDK16这样验证才算真正跑起来3.1 基础验证java -version和HelloWorld装好之后别急着部署业务先用最基础的方式验证一下。也就是我们常用的java -version javac -version直接在ARM机器上输入观察输出。如果能看到java version 16.0.2以及Java(TM) SE Runtime Environment字样至少说明JVM能正常启动。接着可以写一个最简单的Java程序public class HelloArm { public static void main(String[] args) { System.out.println(Hello, JDK16 on ARM); } }编译和运行javac HelloArm.java java HelloArm这一步是为了确认javac编译器也能正常工作。JDK和JRE不一样如果只需要运行Java程序装JRE就行但要做开发或者编译就得有完整的JDK。我自己习惯直接装JDK省得以后写代码时缺少javac。3.2 用系统属性确认运行架构很多人看到java -version里显示64-Bit就放心了其实还不够严谨。有些嵌入式环境是64位内核跑了32位用户态这种情况下JVM也可能是32位的。为了彻底确认当前JVM运行的架构可以写一段更小程序的代码或者直接在JShell里执行jshell然后输入System.getProperty(os.arch); System.getProperty(sun.arch.data.model);os.arch返回aarch64说明是64位ARM JVM返回arm则说明是32位JVMsun.arch.data.model返回64或32则直接告诉你位宽。这一步在排查容器部署问题时特别有用因为容器里看到的架构不一定和宿主机一样。3.3 试试JDK16的新语法JDK 16虽然是个过渡版本但引入的语法特性相当多最典型的就是record、instanceof模式匹配、Stream.toList。这些特性在ARM平台上和在x86_64平台上行为完全一致这也是Java跨平台能力的一种体现。可以在ARM机器上跑一下这段代码验证JDK 16的新语法public class NewFeatures { record Point(int x, int y) {} public static void main(String[] args) { Object obj new Point(3, 5); if (obj instanceof Point p) { System.out.println(Point: p.x() , p.y()); } var list java.util.stream.Stream.of(a, b, c).toList(); System.out.println(list); } }编译运行后如果正常输出说明JDK16的完整编译器在ARM上没有任何缩水。这一点对有“同一个Jar包同时跑在不同架构服务器上”需求的团队影响很大用JDK16的新语法写代码在ARM上编译出的class和x86上编译出的classJVM都能正确加载运行。3.4 启动参数和实际调优ARM设备的内存配置通常比x86服务器紧张JVM启动参数需要更谨慎一些。以我常用的一个Java服务为例java -Xms256m -Xmx1g -XX:UseG1GC -jar myapp.jar-Xms设置堆初始大小-Xmx设置堆最大值-XX:UseG1GC指定G1垃圾收集器。JDK 16默认就是G1在大多数场景下不用额外指定。如果设备内存确实有限可以把-Xmx压到512m同时观察Full GC频率别让堆太小导致频繁GC拖垮吞吐。如果你手头的机器内存比较大比如开发板配了8G以上内存可以尝试ZGC。不过JDK16里ZGC还是实验特性需要解锁参数才能使用生产环境使用前一定要经过充分测试。我一般在嵌入式设备上不推荐ZGCG1在低内存场景下表现更稳定。4. 安装与使用过程中踩过的坑4.1 Exec format error八成是架构不匹配最典型的报错长这样bash: ./java: cannot execute binary file: Exec format error这个报错第一次遇到时很容易懵但排查思路其实很清晰JDK二进制文件和当前系统CPU指令集不匹配。要么是你在ARM机器上下了x86_64包要么是你下载了32位ARM包但内核或用户态是64位。遇到这个报错直接回到第2章重新确认架构多花两分钟比瞎折腾一小时强。另外还要注意有些机器表面上是ARM处理器但系统是32位用户态你下载aarch64的JDK也会报Exec format error。反过来64位系统通常能运行armhf的32位程序如果系统配置了兼容库的话。这就是为什么要确认dpkg --print-architecture和uname -m两个结果的原因。4.2 GLIBC版本不够JDK版本和系统库脱节另一个高频报错是./java: /lib/aarch64-linux-gnu/libc.so.6: version GLIBC_2.32 not found (required by ./java)这个报错说明系统自带的glibc版本低于JDK 16编译时候的要求。JDK 16是2021年的产物对系统库的版本要求并不低如果目标机还是CentOS 7或者更老的Ubuntu直接跑JDK16就会遇到这个坑。解决办法有三个第一升级整个操作系统到新版本这是最彻底的方式第二换用对系统依赖更低的JDK版本比如JDK 8或JDK 11第三手动升级glibc但这是高风险操作强烈不建议在生产环境直接搞很可能把系统搞挂。我在实际项目中遇到老系统时更倾向于换JDK版本而不是硬上JDK16。4.3 32位ARM设备JDK16基本没戏如果你的目标机是armv7l并且系统是32位那前面也提到了官方JDK 16没有armhf的包。这种情况下有两条现实路线降级到JDK 8的ARM版本老系统配合老JDK兼容性最好。改用Azul Zulu或Adoptium Temurin提供的armhf版本它们在较新版本上还保留了32位ARM支持。至于自己下载OpenJDK源码去交叉编译这个过程非常繁琐需要准备交叉编译工具链、处理大量依赖问题、还要理解OpenJDK的构建系统。我不太建议第一次接触ARM的人尝试除非你真的需要JDK 16的某个新特性且设备完全没有升级空间。4.4 和JDK17如何选择怎么选不踩雷现在网上搜“jdk17 arm下载地址”的人很多这也说明大家其实都在关心长期支持版本。我的建议是新项目直接上JDK 17 ARM版因为17是LTS能获得更长时间的安全更新和维护。但如果你的业务框架锁定了JDK 16或者只是临时验证某个技术方案那JDK16 ARM版也完全可以跑只是要接受它已经过维护期的事实。实际部署时我习惯把JAVA_HOME做成软链来管理sudo ln -s /opt/jdk-16.0.2 /opt/jdk这样以后换JDK版本时只需要修改软链指向不需要改动任何脚本和服务配置。这个方法在很多生产环境里都用得上可以避免因为版本切换导致的乱七八糟的路径问题。根据我自己的实际操作体会在ARM设备上折腾JDK16最核心的一件事就是把架构确认清楚。不管是飞腾、鲲鹏还是树莓派只要架构识别对了JDK16在ARM上的体验和x86_64上几乎没差别。很多看起来诡异的报错到最后都指向同一个问题下载的包和系统不匹配。如果你也准备在ARM设备上部署Java服务建议别急着下载先花两分钟把目标机的架构、glibc版本、系统位数都确认好后面真的会顺利很多。本文还有配套的精品资源点击获取
返回列表