☰
ARM版OpenJDK 11安装部署全攻略:下载、配置与避坑指南
2026/10/13 5:35:08 网站建设 项目流程

简介:一个面向ARM架构Linux系统的OpenJDK 11完整工具包,特别适配中标麒麟、银河麒麟等国产操作系统,适合ARM服务器、嵌入式设备及信创场景下开发或部署Java应用。包内含HotSpot虚拟机、javac/java/jshell等核心工具,从根本上解决x86版JDK无法在ARM平台原生运行的问题。压缩包共492个文件,约173.88MB,除了bin目录下的可执行命令,还包含jmod模块文件、so动态库、man手册页、JNI头文件、jar工具包及security/legal等配置与许可文件,结构完整,便于配置JAVA_HOME后直接接入开发或生产环境。目前已有3238人学习下载。借助这套开源JDK,开发者能完成从源码编译、依赖打包到运行监控的全流程操作,并受益于HotSpot在ARM指令集上的深度优化;同时开源许可允许按需查看和分发,为国产化替代与自主可控技术栈提供了可靠的Java基础环境。 前两天在整理一块 ARM 开发板的时候,又把那串很长的文件名翻了出来:OpenJDK11U-jdk_arm_linux_hotspot_11.0.8_10.tar.gz。这包在 OpenJDK 下载页里看着不起眼,但里面装的是能在 ARM Linux 上跑 Java 程序的完整 JDK,带官方 HotSpot 虚拟机,版本是 11.0.8,build 10。对搞嵌入式、玩树莓派或者做 ARM 服务器的人来说,部署 JDK 是绕不开的一步;对新手来说,第一关反而是看不懂这个文件名该不该装。这篇文章就围绕这个包,把 ARM 版 OpenJDK 11 的下载、安装、环境变量配置和常见坑都讲清楚。

1. 从文件名拆起:每个字段都对应一个部署决策

1.1 OpenJDK11U、hotspot、arm_linux 分别代表什么

这个文件名不是随便起的,拆开看就明白自己拿到的到底是个什么东西:

文件名片段含义部署时要注意什么
OpenJDK11U基于 OpenJDK 11 的 update 分支适合 Java 11 应用,不是 Java 8 也不是 Java 17
jdk完整 JDK,不是精简 JRE自带 javac、jcmd、jlink、jmods
arm_linuxARM 32 位 Linux 平台对应设备上 uname -m 通常是 armv7l / armv6l
hotspotHotSpot 虚拟机官方默认 VM,兼容性和资料最全
11.0.8_10版本号 11.0.8,build 10这是 2020 年的版本,适合老项目固定版本用

我见过不少人在这一步就翻车:在 64 位 ARM 设备的 Linux 上看到文件名里有 arm,就直接下载这个包,结果java -version跑不起来。这里的arm_linux在 AdoptOpenJDK 的命名体系里特指 32 位 ARM,你要是用的是aarch64系统,得去找文件名里带aarch64_linux的包。

1.2 为什么我倾向于直接下 tar.gz,而不是靠系统包管理器

很多 ARM 板子的系统是精简过的,apt install openjdk-11-jdk不一定能用,或者仓库里的版本老到离谱。tar.gz 的好处是完全不依赖包管理器,解压就能用,路径可控,版本可控。尤其是离线环境,包管理器的依赖解决能力基本帮不上忙,还不如手动下载一个 tar.gz 传到板子上。

这个包是当年 AdoptOpenJDK 项目发版的,后来相关构建归并到 Eclipse Temurin 名下。老版本归档里还是保留了这个文件名。如果你不是非 11 不可,也可以去 Temurin 的下载页看 17、21 的版本;但今天这篇的主角就是11.0.8_10。

2. 动手之前先确认:这台设备到底该装 arm 还是 aarch64

2.1 用 uname 一行解决主要问题

先把板子系统跑起来,在终端里执行:

uname -m cat /etc/os-release

如果输出是armv7l或armv6l,说明是 32 位 ARM 用户态,本文这个包大概率可用。如果输出是aarch64,那就别费劲了,去下aarch64_linux版本。lscpu | grep Architecture也能看,但uname -m最直接。

这里有个容易误判的点:很多新型号的 ARM 芯片本身是 64 位的,但板子出厂装的是 32 位系统,或者用户自己刷成了 32 位系统。这时候芯片是 64 位,不代表你这个系统能跑 64 位 JDK。判断标准永远是系统当前识别的架构,不是芯片型号。

2.2 浮点 ABI、glibc 版本这些隐藏条件

下载arm_linux包之前,最好确认两件事:第一是系统的 EABI/浮点模型,第二是 glibc 版本。这个arm_linux包通常对应 ARM hard-float ABI,也就是常说的armhf。如果你的系统是软浮点,或者工具链不带 hard-float 支持,运行 JVM 的时候大概率直接报段错误。

快速验证方式:

ldd --version

看到版本太老的话,JVM 可能因为缺少符号起不来。另一个办法是解压后对二进制执行file:

file /opt/java/jdk-11.0.8+10/bin/java

能看到类似ELF 32-bit LSB executable, ARM, EABI5...的输出,就说明这个二进制确实是 32 位 ARM 程序。如果你拿到的输出是aarch64,那就是把包下载错了。

3. 从下载到解压:一套能在离线环境复用的操作流程

3.1 下载安装包并做完整性校验

如果板子能联网,直接下载:

wget https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_arm_linux_hotspot_11.0.8_10.tar.gz

如果板子不能访问外网,就在 x86 主机上下好,再用 scp 或 U 盘拷贝过去。无论哪种方式,下载完第一件事不是解压,而是校验:

sha256sum OpenJDK11U-jdk_arm_linux_hotspot_11.0.8_10.tar.gz

去发布页面找到对应的 SHA256 值比对一下。我遇到过很多次下载过程中断、文件缺一半的情况,这时候解压会报gzip: stdin: not in gzip format。别急着怀疑网络,先看文件大小对不对。

3.2 解压和目录规划

sudo mkdir -p /opt/java sudo tar -xzf OpenJDK11U-jdk_arm_linux_hotspot_11.0.8_10.tar.gz -C /opt/java sudo ln -s /opt/java/jdk-11.0.8+10 /opt/java/openjdk11

我建议把解压后的版本目录和软链分开。jdk-11.0.8+10这个真实目录带版本号,以后升级到 11.0.9 再解压一个目录,软链/opt/java/openjdk11指过去就行,应用配置里的JAVA_HOME不用改。这个习惯在 ARM 板子上尤其重要,因为嵌入式设备重装系统成本高,能少改一处是一处。

3.3 配置环境变量

对 Debian/Ubuntu 类的系统,放到/etc/profile.d/jdk11.sh里最省事:

sudo tee /etc/profile.d/jdk11.sh >/dev/null <<'EOF' export JAVA_HOME=/opt/java/openjdk11 export PATH="$JAVA_HOME/bin:$PATH" EOF source /etc/profile.d/jdk11.sh

如果只是给当前用户用,就把同样内容写进~/.bashrc。但要注意,systemd 服务不会读取/etc/profile.d,也不会读取.bashrc。你后续写服务文件时,必须在[Service]里显式配置:

Environment=JAVA_HOME=/opt/java/openjdk11 Environment=PATH=/opt/java/openjdk11/bin:/usr/bin:/bin

4. 装完以后别急着写代码,先把这几项验证做了

4.1 版本和路径验证

java -version javac -version which java

正常输出里会看到openjdk version "11.0.8"和build 11.0.8+10。which java的路径应该指向/opt/java/openjdk11/bin/java。如果你执行java -version显示的是别的版本,多半是PATH里还有其他 JDK 目录在前面。可以用update-alternatives手动指定优先级,但我更喜欢直接检查echo $PATH,把不想要的路径挪掉。

4.2 用一个最小程序确认 ARM 下运行正常

cat > /tmp/Hello.java <<'EOF' public class Hello { public static void main(String[] args) { System.out.println("OK:" + System.getProperty("os.arch")); } } EOF javac /tmp/Hello.java java -cp /tmp Hello

这里会打印OK:arm,如果是 64 位版则打印OK:aarch64。这一步能一次性验证 javac 编译器、JVM 运行时和文件系统权限,比单纯看java -version更有价值。跑完再把应用 jar 放上来,基本就不会有平台层面的意外了。

4.3 查看 JVM 默认参数,方便后面调内存

ARM 板子内存普遍不大,先看一下 JVM 对自己的预期:

java -XshowSettings:vm -version

把Max Heap Size、Initial Heap Size看清楚。这块板子如果只有 512MB 内存,默认堆也许只有 128MB 左右,看着能用,但跑 Spring Boot 这类框架还是偏紧。我会在启动脚本里加一句:

JAVA_TOOL_OPTIONS="-Xms64m -Xmx256m"

JAVA_TOOL_OPTIONS会被所有 Java 进程读取,调试阶段方便,但线上环境最好还是把参数写进应用的启动脚本,避免影响其他 Java 程序。

5. 那些我踩过的 ARM 板子上的 JDK 坑

5.1 文件明明在,却报 No such file or directory

这个坑排第一,因为排查方向最容易跑偏。你在 ARM 板上解压完包,执行./java,系统告诉你No such file or directory,但ls看得清清楚楚文件就在那。

原因多半是二进制格式不匹配。如果下载的是 32 位 ARM 包,但系统是 64 位内核且没有安装 32 位运行库,内核找不到对应动态链接器,就会给出这个误导性错误。用readelf -l查看:

readelf -l /opt/java/openjdk11/bin/java | grep interpreter

然后确认系统里有没有对应的 loader。更直接的方案是重新下载架构匹配的包。不要在这个问题上耗太久,uname -m一行就能避免绝大多数误判。

5.2 下载不完整导致 tar 解压失败

有一次我在板子上直接wget这个 tar.gz,网络不稳下载到 90% 就断了,wget返回了非零退出码,但我没注意,继续执行tar -xzf,结果报gzip: stdin: not in gzip format。这个报错很常见,不要怀疑是文件损坏,先查大小和 SHA256。

重下的时候我习惯先删掉旧文件再下,不要用wget -c续传。原因很简单:如果服务器返回的是个错误页,或者传输中数据本身已经错位,续传只会把这个错位文件补得更完整,但哈希还是对不上。删掉重来最省心。

5.3 systemd 服务里找不到 JAVA_HOME

终端里source /etc/profile.d/jdk11.sh之后,java跑得挺好。一旦写成 systemd 服务,服务日志就是java: command not found或者JAVA_HOME为空。这不是 JDK 装错,而是 systemd 不会加载 shell profile 环境变量。

解决方式就是在服务文件里写透:

[Service] Environment=JAVA_HOME=/opt/java/openjdk11 Environment=PATH=/opt/java/openjdk11/bin:/usr/bin:/bin ExecStart=/opt/java/openjdk11/bin/java -jar /opt/app/app.jar

嵌入式设备上跑服务,我建议所有路径都写绝对路径,别指望PATH。这不是保守,是省得排查。

5.4 内存不足导致 JVM 启动失败

有的精简 ARM 系统里默认堆参数在你启动服务时会把内存直接吃光,报There is insufficient memory for the Java Runtime Environment to continue。先看free -m确认真实可用内存,再设置固定堆:

java -Xms64m -Xmx256m -jar /opt/app/app.jar

如果设备内存确实非常小,还可以考虑用-XX:MaxRAMPercentage=50这类百分比参数,让 JVM 根据机器内存自动决定,而不是写死数值。但百分比参数在不同版本里表现有差异,嵌入式环境我宁可写死,至少行为可预期。

6. 延伸:用 ARM JDK 不等于要交叉编译,Java 应用一般不用管它

6.1 Java 字节码的平台无关性

有些朋友搜到这个安装包是看到一个完整的 JDK,接着就想去折腾交叉编译工具链。这里要先分清概念:你在这块 ARM 板上用的 Java 应用,一般不需要交叉编译。.class文件和.jar包是平台无关的,你在 x86 机器上javac编译完,直接在 ARM 板子上跑,只要 JDK 版本一致就基本没差别。

真正需要 ARM 交叉编译的是两类东西:一类是 JVM 本身,你下载这个 tar.gz 就是别人已经交叉编译好的原生 ARM 版 JVM;另一类是 Java 里通过 JNI 调用的 C/C++ 原生库.so。如果你只是写纯 Java 业务代码,把交叉编译这件事忘掉就行。

6.2 如果涉及 JNI,怎么判断原生库是否匹配

假设你的应用有 native 目录,里面放了一个libfoo.so,加载时遇到UnsatisfiedLinkError。先执行:

file /opt/app/lib/libfoo.so

如果输出是ELF 32-bit LSB shared object, ARM,那架构层面是对的;如果输出是x86-64,那不用问,肯定跑不了。如果是一台 64 位系统,但你下载的是 32 位 ARM JDK,这个.so也必须是 32 位 ARM 版本,否则 JNI 那边一样崩。这类问题排查顺序永远是:先看os.arch,再看.so的架构,最后看链接库依赖。

6.3 老版本 JDK 要不要升级

这个包是 11.0.8,放在今天确实不算新。但嵌入式项目里面最常见的情况不是追求新版本,而是项目在开发时就用这个版本测过,升级 JDK 带来的潜在问题比旧版本的安全补丁更让人头疼。我的建议是:如果应用已经稳定,先用这个版本把业务跑通;等你有完整的回归测试环境了,再考虑升级到最新的 11 或直接跨到 17、21。

在 ARM 板子上装 JDK,说穿了就这几件事:架构别搞错,tar 包别下坏,JAVA_HOME写明白,内存参数给够。把今天这些步骤过一遍,后面就跑得很稳了。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询