资讯动态

ARM 服务器上安装 JDK 8u321 aarch64:从解压到分布式部署

发布时间:2026/10/20 20:18:19 来源:尧图企业网站定制
简介面向Linux AArch64架构服务器的JDK 8u321二进制发行包适用于运维工程师、后端开发及分布式系统技术人员可满足ARM64节点上部署Java运行环境、推进微服务与大数据集群建设等需求。包内共406个文件整体约71.02MB包含javac、java、jstack、jmap、jcmd等核心命令以及so动态库、jar包、properties配置、cacerts安全证书、man手册与许可文本既有编译、运行、监控JVM的常用工具也提供类库分析、安全认证与动态代理等支持文件解压后目录结构清晰。该资源已有1672人学习下载适合需为ARM架构服务器配置标准JDK、并希望在各节点或容器中保持环境一致的团队使用也可用于构建Docker或Kubernetes基础镜像减少环境差异带来的部署问题。凭借这套完整组件可免去零散找包与拼装文件的成本后续无论进行参数调优、内存溢出排查还是分布式组件部署都能获得可靠的基础保障。1. JDK 8u321 的 aarch64 构建为什么 ARM 服务器上卡住你的往往是 JDK拿到jdk-8u321-linux-aarch64.tar.gz这个文件时你大概已经过了「哪个版本 JDK 都无所谓」的阶段。x86_64 的 JDK 镜像随手就是但换到 ARM 架构的 Linux 服务器——无论是某云平台的 ARM 实例还是机房里的鲲鹏/飞腾机器——很多开发者的第一反应还是去找 x86 的安装包解压之后java -version直接报cannot execute binary file或者干脆没反应。这个包解决的就是这一类「架构不匹配」的窘境它是 Oracle JDK 8 的 8u321 版本专门为 Linux 上的 aarch64ARM 64 位架构编译的二进制发布包。8u321 是 2022 年 1 月发布的季度安全更新版对应 2022 年 1 月 18 日的公告补了一堆安全漏洞对还在维护老项目的团队来说这是 JDK 8 生命周期里一个比较稳的落点——比它老的版本有 CVE比它新的版本改动大。这篇内容面向的是 Linux 运维和分布式环境里干活的人装 JDK、配环境变量、批量同步到多台节点、验证跑起来的完整过程以及那些不翻车都不知道的坑。2. 安装前必须搞清楚的三件事架构、版本、二进制来源2.1 确认你的机器真是 aarch64而不是 armv7 或 armhfARM 的 Linux 服务器不是一个统一体。aarch64 是 64 位 ARM 架构对应的是 ARMv8-A 及以上的 CPU而 armv7、armhf 是 32 位。用uname -m看输出如果是aarch64这个包就能用如果输出armv7l或者armv8l那其实是 32 位用户态装这个包会直接翻车。uname -m # 输出示例aarch64 # 或者用 dpkg / rpm 看系统架构 dpkg --print-architecture # Debian/Ubuntu 系输出 arm64 是对的 rpm -q --qf %{ARCH}\n --whatprovides /etc/redhat-release # CentOS/RHEL 系输出 aarch64 是对的逻辑说明uname -m看的是内核和用户态二进制格式的架构不是 CPU 型号。一台 CPU 支持 64 位但系统装的是 32 位用户态uname -m也会显示armv8l这种情况下 JDK 的 aarch64 二进制是跑不起来的。dpkg或rpm看的是发行版打包目标架构更准确。参数说明在 x86_64 服务器上uname -m输出是x86_64不要和aarch64搞混这俩不是同一个东西。2.2 这个版本号怎么读8u321 意味着什么JDK 8 的版本号规则是8u安全更新编号。8u321 是 2022 年 1 月 18 日发布的季度安全更新也就是 2022 年第一个 CPUCritical Patch Update版本。对它之前的 8u311、8u302 等版本是累积性替代修了一堆漏洞。对运维来说选版本号的基本原则是「在老项目能跑的前提下尽量取较新的 CPU 版本」——老项目一般不敢跨大版本升 JDK但小版本安全更新是要追的。这个 tar.gz 包内部路径带有jdk1.8.0_321目录名解压后注意路径里有个1.8.0_321的表示方式对应的是java -version输出里的1.8.0_321。2.3 tar.gz 和 rpm/deb 的差异以及为什么选 tar.gzOracle 官方为 Linux aarch64 提供两种打包形式tar.gz 和 rpm。rpm 包适合单机快速安装会自动写/usr/bin/java符号链接和系统级配置但缺点是路径不灵活、多版本切换麻烦而且卸载的时候可能连带把别的依赖带走。tar.gz 是纯二进制压缩包解压就能用非常适合「把 JDK 放到/opt底下然后软链到自定义位置」这种运维习惯。我一般会选择 tar.gz 做分发原因很实际分布式环境里多台机器要装同一个 JDKtar.gz 解压后可以直接打包再分发rpm 则需要处理依赖和签名。而且 tar.gz 可以解压到任意目录不会污染系统目录出问题直接删目录就能「后悔药」。缺点是环境变量要自己配但这个成本一次性的后面批量操作反而更统一。3. 解压、路径规划、多版本切换一套能直接用的安装流程3.1 规划安装目录别装在 /usr/local 底下直接塞Linux 上管理 JDK 有几个常见位置/usr/lib/jvmRPM 安装默认路径、/opt第三方软件常见路径、/usr/local手动编译安装默认路径。我习惯放在/opt/jdk下面因为/opt专门放第三方软件不容易和系统自带的东西冲突而且多版本 JDK 场景下/opt/jdk/jdk1.8.0_321和/opt/jdk/jdk-17并列放切换版本只是改个软链的事。# 假设安装包已经上传到 /root 目录 mkdir -p /opt/jdk tar -xzf jdk-8u321-linux-aarch64.tar.gz -C /opt/jdk ls -la /opt/jdk/ # 你会看到解压出来的目录/opt/jdk/jdk1.8.0_321逻辑说明tar -xzf的-C指定了解压目标目录JDK 包内部自带一层目录结构所以不会把文件散落在/opt/jdk根下。参数说明-x是解压-z是通过 gzip 解压-f指定文件名这三个参数组合是 tar.gz 解压的标准姿势。解压后你应该看到jdk1.8.0_321这个目录而不是直接把bin/、lib/散出来——如果散出来了说明包的目录结构设计不同但你依然可以用ls确认bin/java是否存在。3.2 环境变量配置一行都不能少配置环境变量是 tar.gz 安装方式和 rpm 安装方式的分水岭。rpm 装完系统自动配好tar.gz 则需要自己写。最稳妥的做法是写进/etc/profile.d/下面而不是直接改/etc/profile。/etc/profile.d/下的.sh文件会在每个用户登录时被 source独立文件的管理方式更清爽以后删掉文件就等于撤销全部配置——这个习惯对后面在多台服务器上同步部署尤其重要。cat /etc/profile.d/jdk8.sh EOF export JAVA_HOME/opt/jdk/jdk1.8.0_321 export PATH$JAVA_HOME/bin:$PATH export CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar EOF source /etc/profile.d/jdk8.sh逻辑说明JAVA_HOME是很多中间件比如 Tomcat、Maven、Gradle启动时必须依赖的环境变量它的值必须是 JDK 安装目录的绝对路径而不是bin/的路径。PATH把$JAVA_HOME/bin放在最前面是为了确保命令行的java、javac是我们要的这个版本而不是系统自带的 OpenJDK。CLASSPATH里.代表当前目录让 Java 运行时的类加载器能找到当前路径下的 class 文件——这个写法在 JDK 8 里是惯例到 JDK 9 之后模块化就不需要设了但 8u321 还是要的。注意source一行是让当前 shell 立刻生效新开的 SSH 会话会自动加载不用重复执行。3.3 验证安装java -version 和 javac -version 都要看装完最少要验证四个输出java -version、javac -version、which java、echo $JAVA_HOME。很多人只跑第一个结果后面 Maven 或 Tomcat 报了JAVA_HOME is not set才回头补环境变量。java -version # 期望输出 # java version 1.8.0_321 # Java(TM) SE Runtime Environment (build 1.8.0_321-b04) # Java HotSpot(TM) 64-Bit Server VM (build 25.321-b04, mixed mode) javac -version # 期望输出javac 1.8.0_321 which java # 期望输出/opt/jdk/jdk1.8.0_321/bin/java echo $JAVA_HOME # 期望输出/opt/jdk/jdk1.8.0_321逻辑说明第二个输出里的64-Bit Server VM是正常的——aarch64 的 JDK 8 默认就是 64 位 Server VM混合模式 mixed mode 表示解释器和 JIT 编译器协同工作。which java检查的是 PATH 生效情况如果指向/usr/bin/java说明你是 rpm 方式装的 OpenJDK 在 PATH 里排在前面需要回头检查/etc/profile.d/jdk8.sh里的 PATH 顺序。echo $JAVA_HOME检查的是环境变量有没有在当前的 shell 里成功加载。3.4 做个软链以后升级 JDK 不用改全局配置软链这个技巧在高版本切换时非常好用。现在的路径是/opt/jdk/jdk1.8.0_321以后如果换 8u341 或 8u351你会得到一个/opt/jdk/jdk1.8.0_341所有配置引用旧路径就要全改一遍。但如果一开始就做一层软链就只需要改一次软链目标。ln -sfn /opt/jdk/jdk1.8.0_321 /opt/jdk/current export JAVA_HOME/opt/jdk/current export PATH$JAVA_HOME/bin:$PATH修改/etc/profile.d/jdk8.sh里的JAVA_HOME为/opt/jdk/current以后升级只需要把新的 JDK 解压到/opt/jdk然后重新指向软链。ln -sfn的-s是符号链接-f是覆盖已有链接-n是当目标是目录时不跟随——这个组合参数在反复重建软链时不会产生嵌套链接。4. 避坑与排查aarch64 JDK 安装中最常见的 6 个翻车点4.1 解压后没有java命令或者文件损坏现象tar -xzf执行完/opt/jdk/jdk1.8.0_321/bin/下没有java可执行文件或者执行java -version报No such file。原因下载的包不完整或者下载过程中被某种校验机制截断了。tar.gz 是压缩格式损坏时解压会正常完成一部分但关键的二进制文件丢了。解决重新下载后用sha256sum校验把官方公布的 SHA-256 校验值拿来比对。sha256sum jdk-8u321-linux-aarch64.tar.gz # 输出得到一个 64 位十六进制字符串和官方页面公布的比对4.2Cannot execute binary file错误现象解压后执行./java -versionshell 报cannot execute binary file: Exec format error。原因机器的 CPU 或系统用户态不是 aarch64或者你实际上把 x86_64 的 JDK 包当成 aarch64 包解压了。解决先uname -m确认架构再看文件名x86_64 包名是jdk-8u321-linux-x64.tar.gzaarch64 包名是jdk-8u321-linux-aarch64.tar.gz这俩如果搞混了你会浪费很多时间。4.3JAVA_HOME配了但java -version还是系统自带的 OpenJDK现象vim /etc/profile.d/jdk8.sh里写好了export JAVA_HOME/opt/jdk/jdk1.8.0_321执行source之后java -version输出的还是OpenJDK或者别的版本。原因其他 profile 脚本或者 shell 的启动文件里把PATH里系统自带 JDK 的bin放在了更前面。解决which java看实际路径然后用echo $PATH检查路径顺序把我们的$JAVA_HOME/bin提到最前面。4.4 Tomcat 或应用启动报Unsupported major.minor version 52.0但 JDK 8 明明是对的现象应用编译是用 JDK 11 或更高版本编译的运行环境是 JDK 8启动时报UnsupportedClassVersionError。原因字节码版本和 JVM 版本不匹配。JDK 8 对应的是 52.0JDK 11 对应的是 55.0。解决要么给应用装 JDK 11要么用高版本 JDK 重新编译。这不是 aarch64 特有的问题但 ARM 机器上很多人因为从 x86 迁移过来顺手把 JDK 版本降了容易忽视这个。4.5 debug 符号缺失或 JIT 编译本地代码段崩溃现象个别服务在高并发压测下hs_err_pid*.log文件刷出来里面报的是SIGSEGV而且出现在libjvm.so的 JIT 编译代码段。原因JDK 8 的 aarch64 移植版在早期版本确实有过一些 JIT 编译器的 bug但 8u321 已经修掉一批。遇到这种情况先确认自己的包是官方版本而不是第三方整合包第三方整合包有的会改 JVM 参数在 ARM 上更容易踩坑。解决换官方 Oracle 包或 OpenJDK 的 aarch64 包然后在catalina.sh或启动脚本里加上-XX:-TieredCompilation临时降级 JIT但这个参数会损失编译性能只能用来定位问题不能长跑。4.6 多用户环境下java命令找到但JAVA_HOME为空现象root 用户跑echo $JAVA_HOME有值切换到某个普通用户后值为空应用启动失败。原因/etc/profile.d/jdk8.sh的权限或者普通用户的 shell 启动逻辑问题。检查文件权限是否至少是644所有人可读以及普通用户的登录 shell 是不是 bash——如果用户用的/bin/sh它不会加载/etc/profile.d/下的脚本。解决确认用户的/etc/passwd里 shell 字段是/bin/bash这个问题在通过 sudo 执行命令时尤其容易踩到因为 sudo 默认不保留环境变量。5. 进阶分布式服务器批量部署与 JDK 状态核验技巧5.1 批量推送ansible 写法与手动脚本的权衡如果你管理着十几台 aarch64 服务器一台台scp加解压效率太低。常见做法是先把 JDK 包解压到一台模板机上把解压好的目录打包然后批量推送到其他节点而不是每台机器都走一遍原始的 tar.gz。这样可以省去每台机器上的解压耗时同时保证所有节点的目录结构完全一致。下面是一个用 bash 写的批量部署脚本不依赖 ansible 也能跑。#!/bin/bash # 批量部署脚本deploy_jdk.sh SERVER_LIST192.168.1.101 192.168.1.102 192.168.1.103 JDK_PKG/opt/jdk/jdk1.8.0_321 REMOTE_DIR/opt/jdk for host in $SERVER_LIST; do echo 部署到 $host ... # 打包并压缩 JDK 目录 tar -czf /tmp/jdk1.8.0_321.tar.gz -C /opt/jdk jdk1.8.0_321 # 传输到远端 scp /tmp/jdk1.8.0_321.tar.gz root$host:/tmp/ # 远端解压并配置 ssh root$host tar -xzf /tmp/jdk1.8.0_321.tar.gz -C $REMOTE_DIR \ ln -sfn $REMOTE_DIR/jdk1.8.0_321 $REMOTE_DIR/current \ cat /etc/profile.d/jdk8.sh EOF export JAVA_HOME/opt/jdk/current export PATH\$JAVA_HOME/bin:\$PATH export CLASSPATH.:\$JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tools.jar EOF source /etc/profile.d/jdk8.sh \ java -version done逻辑说明循环里每台主机都重复「打包、传输、远端解压、配软链、写配置、验证」这一套。\$JAVA_HOME里的反斜杠转义是为了防止本机 shell 在生成 heredoc 时提前展开变量——这个细节最容易翻车不转义的话远端的配置文件里写的是空字符串。参数说明SERVER_LIST可以用空格分隔多台主机JDK_PKG指向模板机上解压好的 JDK 目录整套脚本用bash deploy_jdk.sh运行。生产环境强烈建议换成 ansible 的synchronize模块或unarchive模块因为 scp 在部分网络环境下速度不稳定synchronize底层是 rsync支持增量同步。5.2 一次性核验全网环境变量和实际版本批量部署完以后别急着收工。写一个简单的巡检脚本把所有节点的 Java 版本收集回来确认不是某些节点还停留在老版本或者架构不对。#!/bin/bash # 巡检脚本check_jdk_all.sh HOSTS192.168.1.101 192.168.1.102 192.168.1.103 for host in $HOSTS; do echo $host ssh root$host echo JAVA_HOME\$JAVA_HOME; which java; java -version 21 | head -n 1 done逻辑说明21把 Java 版本输出里的错误流合并到标准输出因为java -version的输出实际上走的是 stderr——这个细节会让不少人在重定向时抓不到版本号。head -n 1只取第一行版本信息减少输出量。参数说明HOSTS 列表和部署脚本保持一致建议把巡检脚本存成check_jdk_all.sh并定期执行尤其是在有人手工操作过某台服务器的/opt/jdk之后。5.3 验证 JVM 是否真的在用 aarch64 的 JIT 编译器java -version的输出只能证明 JVM 能启动不能证明 JIT 编译器用的是针对 AArch64 的实现。想看 JIT 实际运作用-XX:PrintCompilation启动一个最简单的 HelloWorld观察编译日志的输出。public class Hello { public static void main(String[] args) { long sum 0; for (int i 0; i 100000; i) { sum i; } System.out.println(sum); } }javac Hello.java java -XX:PrintCompilation Hello # 输出大量类似这样的日志 # 48 1 3 java.lang.String::hashCode (55 bytes) # 57 2 3 java.lang.Object::init (1 bytes) # 后面跟的架构相关日志行会包含 aarch64 字样如果用 -XX:LogCompilation -XX:LogFile... 看详细日志逻辑说明-XX:PrintCompilation是打印 JIT 编译活动看到 Java 方法被编译成机器码的记录说明 HotSpot 的 C1/C2 编译器在工作。要更进一步确认编译架构用-XX:LogCompilation -XX:LogFile/tmp/compilation.log生成详细日志搜索aarch64字符串。如果日志里一直搜不到架构相关字段检查是不是用了-Xint纯解释模式——那会禁用 JIT性能差距可能达到 10 倍以上。这个验证方法在分布式环境里价值很大因为 ARM 服务器经常被当作低配机器实际上 aarch64 的 JIT 配合上合适的参数在大部分业务场景下都不会成为瓶颈。5.4 GC 参数在 aarch64 上的调法别把 x86 的参数直接搬过来JDK 8 的 aarch64 移植版本支持-XX:UseG1GC但不支持-XX:UseConcMarkSweepGC——CMS 在 JDK 8 里虽然在 x86_64 上还可用于部分场景但在 aarch64 移植版上有些版本直接不支持。你如果是从旧的 x86 服务器迁移过来启动脚本里还带着 CMS 参数那在 ARM 机器上会遇到启动失败或参数被忽略。建议直接切到 G1JDK 8 的 G1 在 aarch64 上的成熟度是可以接受的。不过这里还涉及一个 8u321 特有的问题由于供应链原因从 8u321 开始的官方 JDK 8 版本中JavaWeb 相关的部署技术已不再包含如果你依赖的是 Java 插件式的 Web 应用那么这一版本可能不适合你。换到 G1 之后还需要配合一个小习惯检查-Xms和-Xmx的设置。ARM 机器上很多是共享内存架构物理内存看着够用但被 NoSQL 或消息队列占了一大块这时候-Xmx设得太大反而会让 GC 频率变高。我一般会把-Xms和-Xmx设成同一个值避免 JVM 动态扩容带来的停顿这个习惯在 x86 上是通用的到了 ARM 上更要遵守因为 ARM 服务器的内核数往往比同价位 x86 机器少JVM 的线程调度更敏感。从那以后我每次在 ARM 服务器上部署 JDK都会强制走一遍「uname -m 确认 → 解压后 sha256sum 比对 → 配 profile.d → 跑 HelloWorld 验证 JIT → 批量巡检所有节点」的流程每一步都是之前血泪经验的产物。这套流程动作不多但每一步都在堵一个真实的坑。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑