简介JRE 1.8 64 位运行环境以解压即用的压缩包形式提供面向需要运行 Java 应用、部署旧版服务或进行兼容性验证的开发与运维人员。它解决的是目标机器缺少 Java 运行时、安装流程繁琐以及多版本共存不便的问题也可用于教学演示和离线环境中的程序启动。压缩包共 239 个文件约 75.08MB涵盖 109 个 dll、27 个 jar、24 个 properties、21 个 exe 以及字体、策略配置和证书信任等组件分别承担本地库调用、核心类库加载、参数配置、启动工具与安全管理等职责目录结构较完整。已有 2293 人学习下载。解压后可直接获得可用的运行时目录便于快速验证 Java 程序、排查环境缺失导致的启动异常也能保留旧项目所需的 8 版本环境减少与其他 JDK 版本互相干扰适合需要稳定运行环境和离线部署的场景。1. 免安装 JRE 1.8 到底解决什么问题一次没有管理员权限的 jar 启动前阵子帮人看一套内网老系统机器是带还原卡的瘦客户端装任何东西都要管理员口令重启一次全部回滚。最后的解法很土U 盘拷一个 jre1.8 的解压包进去改两行 PATHjar 就跑起来了。这个包的本质就一句话——Java 8 的运行时环境只负责跑 class 和 jar不带编译器、不写注册表、不碰系统目录解压到哪就在哪活着。它解决的不是我要写 Java而是我手上有个 jar 必须跑但这台机器不许我装东西。适合三类人给老应用续命的运维、把工具打成绿色包交付的开发者、以及要在隔离环境里精确复现某个 Java 8 行为的人。反过来你要编译代码它帮不了你这是两回事。2. 解压之后先别配环境变量JRE 目录里真正决定能否启动的 6 个文件很多人拿到压缩包的第一反应是解压完立刻配 JAVA_HOME结果配错了还不知道错在哪。先花五分钟把目录看明白后面能省掉一半的排查时间。一个完整的 JRE 8 目录其实很薄绝大多数文件是可选的资源真正决定能不能起来的只有六个。2.1 从目录结构反推启动链路解压出来一般长这样版本号后缀各家打包方式不一样但骨架稳定jre1.8.0_xxx/ ├── bin/ │ ├── java.exe 启动器负责找 jvm.dll 并把参数传进去 │ ├── javaw.exe 同一个东西的无控制台版本 │ ├── keytool.exe 证书库管理排查 HTTPS 问题全靠它 │ ├── jjs.exe Nashorn 脚本引擎 │ ├── jcontrol.exe 部署控制台纯后端项目可以删 │ ├── client/ 32 位客户端模式虚拟机部分包已移除 │ └── server/ │ └── jvm.dll 虚拟机本体真正干活的 ├── lib/ │ ├── rt.jar 核心类库java.lang / java.util 都在里面 │ ├── charsets.jar 扩展字符集 │ ├── jce.jar 加密扩展 │ ├── jsse.jar TLS/SSL 实现 │ ├── ext/ 扩展 jar本地化数据、zipfs、nashorn │ ├── security/ │ │ └── cacerts 信任根证书库HTTPS 握手用它 │ ├── fonts/ 字体图形界面渲染中文靠它 │ └── management/ JMX 相关 └── release 纯文本元信息记录版本和架构关键点在于java.exe只是一个壳它按相对路径去找..\lib\amd64\jvm.cfg64 位或者..\lib\i386\jvm.cfg再根据里面的配置加载bin\server\jvm.dll。这几个路径是硬编码的相对关系所以整个目录可以整体搬家但目录内部一个都不能少。你把 bin 单独拷出来它必然起不来。路径作用缺失后的表现bin/java.exe启动入口什么都跑不了bin/server/jvm.dll虚拟机本体报找不到 jvm.dll 或 jvm.cfglib/rt.jar核心类库报 NoClassDefFoundError: java/lang/Objectlib/charsets.jar扩展字符集部分编码转换抛异常或乱码lib/security/cacerts信任证书库内网 HTTPS 报 PKIX path building failedlib/fonts字体图形界面中文显示成方块至于lib/ext下面的东西属于用到了才有事的类型。本地化数据缺了日期格式化的某些 Locale 会退化zipfs 缺了用 FileSystems.newFileSystem 读 zip 会失败。生产环境别删做精简交付时再按场景动手。2.2 三条命令验明正身版本、位数、发行信息配环境变量之前先直接进 bin 目录敲命令确认这个包是完整且可用的。用绝对路径调用绕开 PATH 里可能存在的其它 java。:: 进入解压目录的 bin/d 用于跨盘符切换 cd /d D:\tools\jre1.8.0_202\bin :: 1) 版本与虚拟机位数重点看是不是 64-Bit java -version :: 2) 打印关键系统属性确认 java.home 指向的就是解压目录 java -XshowSettings:properties -version 21 | findstr /i java.home java.version os.arch file.encoding user.language :: 3) 证书库能不能打开条目数是否正常通常几十到一百多条 keytool -list -keystore ..\lib\security\cacerts -storepass changeit | findstr /c:Your keystore contains逻辑说明-XshowSettings:properties会让虚拟机在启动阶段把全部系统属性打到标准错误然后正常退出是检查一个陌生 JRE 最省事的办法1.8 全系都支持。21不能省这些信息走的是 stderr管道接不上就什么都看不到。findstr /i忽略大小写过滤Windows 上比 grep 稳。参数说明java.home输出必须等于你解压的那个目录。如果它指向别处说明 PATH 里另一个 java.exe 抢在前面了这一步就当没做。os.arch是amd64表示 64 位是x86表示 32 位——这个值决定了后面能不能加载 64 位的本地库用错了会报Cant load this .dll on a AMD 64-bit platform。file.encoding在 1.8 上默认跟随系统区域设置中文 Windows 上一般是 GBK这就是后面乱码问题的根子。keytool那条里的changeit是证书库的公开默认口令绝大多数发行包都没改过。如果这条报 Keystore was tampered with, or password was incorrect说明包被二次处理过得找交付方要口令。还有一处不要漏release文件是纯文本直接打开看JAVA_VERSION和OS_ARCH两行比任何命令都快而且不需要它能跑起来。2.3 落位路径、权限和只读介质的三个注意点包验完了接下来决定放哪。这一步看着琐碎但我见过至少一半的玄学问题出在这里。第一路径不要带空格和中文。JAVA_HOME会被各种启动脚本拼接成%JAVA_HOME%\bin\java.exe再去调用一旦路径里有空格脚本作者忘了加引号就直接断在半路中文路径在 GBK 与 UTF-8 之间来回转换时某些老工具会拼出乱码文件名。统一放到D:\tools\jre1.8.0_202或/opt/jre1.8.0_202这种干净路径下能省掉一整类问题。第二Windows 上别塞进C:\Program Files。那个目录默认需要管理员权限才能写而 JRE 在某些场景下是要写东西的比如-XX:HeapDumpOnOutOfMemoryError默认往当前目录扔 dump、lib/security/cacerts导入证书时要落盘。放用户目录或者独立的 tools 盘更合适。第三Linux 上解压后必须补执行权限压缩包经过 Windows 中转经常把权限位丢掉# 递归补上可执行位只对 bin 目录生效 chmod -R x /opt/jre1.8.0_202/bin # 验证一下输出应该是 755 左右 ls -l /opt/jre1.8.0_202/bin/java # 直接调用不依赖 PATH /opt/jre1.8.0_202/bin/java -version另外别把 JRE 放在/tmp下。不少加固过的系统给/tmp挂了noexecjvm.dll或者libjvm.so加载时会被内核直接拒绝报的错还特别含糊Failed to write core dump之类。同理只读挂载的介质上部署时cacerts是没法导入新证书的需要先把它拷到可写目录再用-Djavax.net.ssl.trustStore指过去。3. JAVA_HOME 与 PATH 怎么指多版本共存下的三种切换方式环境变量这件事配对了是背景配错了是灾难。JRE 场景下最容易犯的错不是没配而是配了但指错了层级以及系统里还有另一个 java 在抢路。3.1 JAVA_HOME 指向根目录PATH 指向 bin规则只有一条JAVA_HOME指向 JRE 的根目录不是 bin。因为大量启动脚本内部写的是%JAVA_HOME%\bin\java.exe你指到 bin拼出来就是bin\bin\java.exe。:: 写入用户级环境变量不需要管理员权限 :: 注意setx 只影响之后新开的窗口当前窗口不会变 setx JAVA_HOME D:\tools\jre1.8.0_202 :: 把 bin 前置到 PATH同样只对后续新窗口生效 setx PATH D:\tools\jre1.8.0_202\bin;%PATH%setx有两个坑要提前知道。一是它有 1024 字符的长度上限PATH 本来就臃肿的机器上直接setx PATH %PATH%;...会把超出部分静默截断后果是某些命令突然找不到了。稳妥做法是先在当前窗口echo %PATH%把原值抄下来备份或者干脆用图形界面的环境变量编辑器逐条改。二是setx不刷新已经打开的窗口改完必须新开一个 cmd 才生效很多人改完在旧窗口里测以为没起作用。验证顺序问题用whereLinux 上是which比java -version更直接:: 按 PATH 顺序列出所有同名可执行文件第一个就是实际执行的那个 where java :: 输出形如 :: D:\tools\jre1.8.0_202\bin\java.exe :: C:\ProgramData\...\javapath\java.exe如果第一条不是你刚配的那个说明前面还有东西挡着。常见的是某些安装器留下的公共转发目录、某些开发工具自带的运行时、以及 32 位系统上C:\Windows\System32里的残留。处理办法不是删容易连带别的软件一起坏而是把自己的路径前置让它在最前面。还有一个只在 JRE 场景下才会遇到的边界某些构建工具和容器启动脚本会去检查%JAVA_HOME%\bin\javac是否存在找不到就直接抛错。这是设计使然——它们需要编译器。JRE 里没有 javac这个错没法绕过只能换 JDK。判断标准很简单你要跑东西还是编东西。3.2 便携启动脚本不改系统环境的那种很多时候你没有权限改系统环境变量或者不想改——比如在客户机器上临时跑一次或者在同一个 shell 里要切换两套 JRE 做对比测试。这时候用会话级脚本更合适。Windows 版放在 JRE 根目录双击得到一个已经配好环境的命令行echo off rem portable-java.bat —— 放在 JRE 根目录双击打开一个临时环境 setlocal rem %~dp0 是脚本所在目录且带尾部反斜杠去掉它避免拼出双斜杠 set JAVA_HOME%~dp0 if %JAVA_HOME:~-1%\ set JAVA_HOME%JAVA_HOME:~0,-1% set PATH%JAVA_HOME%\bin;%PATH% echo JAVA_HOME%JAVA_HOME% java -version rem /k 保持窗口不关方便继续敲命令 cmd /k逻辑说明setlocal是关键它把环境变量的修改限制在这个批处理进程及其子进程里窗口关掉就完全消失不污染系统。%~dp0展开成脚本所在目录并带尾部反斜杠直接拼\bin会得到...\jre\\bin多数情况能跑但某些脚本解析会出问题所以用%VAR:~-1%取最后一个字符判断后截掉。cmd /k让子 shell 继承这套环境并保持打开。整个脚本跟着 JRE 目录走拷到哪都能用。Linux 版用 source 而不是直接执行否则 export 只影响子进程#!/usr/bin/env bash # jre-env.sh —— 用 source jre-env.sh 加载到当前 shell # BASH_SOURCE[0] 在 source 场景下同样指向脚本自身路径 JRE_ROOT$(cd $(dirname ${BASH_SOURCE[0]}) pwd) export JAVA_HOME$JRE_ROOT export PATH$JAVA_HOME/bin:$PATH java -version参数说明cd ... pwd这一串是为了把相对路径转成绝对路径直接用dirname拿到的是相对路径cd到别处后JAVA_HOME就失效了。这种写法在任何目录下 source 都能得到正确结果。多版本对比测试时我会开两个终端各 source 一份不同版本的脚本互不干扰。这比改系统环境变量再重启终端快得多也更适合排查到底是版本问题还是代码问题。3.3 IDE 与构建工具里怎么指过去开发机上装了完整 JDK 的人通常也会把这个免安装 JRE 注册进 IDE做两件事跑 jar、模拟客户环境。IDE 的 SDK 配置界面里把它添加成一个 JRE 条目路径选根目录。然后运行配置的 JRE 选它就行。注意 IDE 的编译动作永远走项目 SDKJDK只有运行配置才走这个 JRE两者是分开的别混。构建工具侧就一个变量JAVA_HOME。这个指向 JRE 会直接翻车报错信息非常经典No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?看到这句就不用往下查了一定是JAVA_HOME指到了 JRE。要么切回 JDK 编译要么改用mvn -o之类只跑不编的目标。同理任何需要javac的打包流程都不能只靠这个包完成。场景需要 JDK需要 JRE说明编译源码 / 打 jar是否没有 javac 直接失败运行现成 jar否是本文主角单元测试需要编译是否测试代码要编译只跑测试产物否是前提是产物已构建好调试远程进程否是加 JDWP 参数即可这张表建议存下来遇到到底装不装 JDK的争论时直接甩出来比解释十分钟管用。4. 无 JDK 也能交付jar 启动参数、绿色工具包与容器镜像瘦身跑起来只是及格线。真正体现功力的地方是怎么让这个包在别人机器上、在没有 JDK 的容器里稳定跑三个月。这一章讲三个高频交付形态。4.1 启动参数1.8 上真正该调的其实就五六个启动参数不是越多越好1.8 上大部分参数调了也没感觉真正影响稳定性的就那么几个。下面这份是我常用的基线java -server \ -Xms512m -Xmx1024m \ -XX:MetaspaceSize128m -XX:MaxMetaspaceSize256m \ -Dfile.encodingUTF-8 \ -Duser.timezoneAsia/Shanghai \ -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/data/dump \ -jar /opt/app/app.jar --server.port8080逐条说。-server让虚拟机选服务端编译模式启动稍慢但长时间运行吞吐更好服务端程序必加桌面小工具反而可以省。-Xms和-Xmx设成一样是常见做法避免堆反复扩容收缩带来的抖动1.8 默认的初始堆很小不设的话前几分钟会频繁 GC。-XX:MetaspaceSize是 1.8 特有的——永久代已经没了类元数据搬到了本地内存不设上限的话某些动态生成类的框架会一路吃光物理内存然后被系统 OOM Killer 干掉日志里什么都看不到。-Dfile.encodingUTF-8决定默认字符集。1.8 在中文 Windows 上默认 GBK读 UTF-8 配置文件必乱码。这个参数还能通过环境变量JAVA_TOOL_OPTIONS注入但我不建议这么做见第 5 章。-Duser.timezone在容器里尤其重要。基础镜像的时区往往是 UTC不指定的话日志时间戳全部差 8 小时排查问题时能把人逼疯。别指望TZ环境变量1.8 对它的支持在早期版本里并不完整。-XX:HeapDumpOnOutOfMemoryError是后悔药。真出 OOM 的时候现场已经没了有这个参数至少能拿到堆快照。HeapDumpPath指向一个有空间的独立目录默认扔在当前工作目录容器里往往就是根分区dump 写到一半磁盘满反而把问题搞复杂。顺带说一句-Xss默认 1m除非你有大量深递归或者海量线程不然不用动。见过有人为了优化把它调到 256k结果栈溢出在生产上随机爆属于自己给自己挖坑。4.2 打成绿色工具包一个目录拷走就能用交付给客户的小工具理想形态是一个文件夹里面自带运行时、jar、配置和启动脚本拷过去双击就能用不需要客户懂什么叫环境变量。目录布局ToolPack/ ├── jre/ 整个 JRE 目录原样放进来 ├── app/ │ ├── app.jar │ └── config/ ├── logs/ └── 启动.bat启动脚本echo off setlocal rem %~dp0 带尾反斜杠直接拼子目录不要再加斜杠 set BASE%~dp0 set JAVA_HOME%BASE%jre set PATH%JAVA_HOME%\bin;%PATH% rem start 后面第一个空引号是窗口标题占位不能省否则路径含空格会解析错 rem javaw.exe 不弹控制台窗口适合给最终用户 start %JAVA_HOME%\bin\javaw.exe ^ -Xmx512m -Dfile.encodingUTF-8 -Duser.timezoneAsia/Shanghai ^ -jar %BASE%app\app.jar几个细节值得较真。start 后面那个空字符串不是多余的start的第一个带引号参数会被当成窗口标题省掉的话整个命令会被误解析表现是窗口一闪而过什么都没发生——这个坑我踩过不止一次。用javaw.exe而不是java.exe最终用户看不到黑框体验完全不一样但要调试的时候得换回java.exe才看得到输出。^是批处理的续行符长命令拆行用注意^后面不能有空格不然会被当成转义空格拼进参数里。打包分发前记得把logs/和config/建好程序第一次启动写文件时目录不存在会直接抛异常。这类问题在开发机上永远复现不了因为目录是手建的。4.3 塞进容器镜像把 JRE 当普通文件拷进去容器场景下从零装 JDK 是浪费。基础镜像里把解压好的 JRE 整目录COPY进去镜像能小几百 MB。Dockerfile 核心部分# 基础镜像选 glibc 系的精简版本换成你手上的即可 # 注意不要把 JRE 放到镜像里再 chmod构建上下文里先处理好权限 FROM your-base-image:tag COPY jre /opt/jre COPY app.jar /opt/app/app.jar ENV JAVA_HOME/opt/jre \ PATH/opt/jre/bin:$PATH \ LANGC.UTF-8 # 1.8 请用 exec 形式的 ENTRYPOINT避免 shell 包装导致信号传不到 JVM ENTRYPOINT [/opt/jre/bin/java,-Xms256m,-Xmx512m,\ -Dfile.encodingUTF-8,-Duser.timezoneAsia/Shanghai,\ -jar,/opt/app/app.jar]逻辑说明ENV PATH里用$PATH引用已有的值Dockerfile 的 ENV 支持这种展开。用 exec 形式JSON 数组的 ENTRYPOINTPID 1 直接是 java 进程docker stop发的 SIGTERM 才能被 JVM 的关闭钩子接住否则要等 10 秒超时才被 SIGKILL优雅停机逻辑全部失效。这里有个 1.8 特有的坑必须提早期版本不感知容器的内存限制。你给容器设了 512MBJVM 看到的还是宿主机的总内存默认最大堆按宿主机内存的 1/4 算容器直接被 OOMKilled日志里干干净净什么都没有。从 1.8u191 开始引入了容器感知支持之后的版本会读 cgroup 限制。分不清手上是哪个小版本最稳的办法就是显式写-Xmx别让它自己算。另外基础镜像用 glibc 系还是 musl 系要想清楚。1.8 的某些本地库对 musl 支持不完整DNS 解析和线程栈大小都可能出问题。不确定的时候选 glibc 系多几十 MB 换稳定。5. 排查现场解压了却跑不起来的 5 个真实翻车点这一章是我自己踩过和帮别人处理过的现场记录按现象 → 原因 → 解决整理。遇到问题时按顺序对一遍八成能定位。一、Error: could not open D:\...\lib\amd64\jvm.cfg现象很直接命令敲下去立刻报这个路径里带的是另一个目录。原因是 PATH 里存在第二个 java.exe而且排在前面——通常是某安装器留下的公共转发目录或者别的开发工具自带的运行时。启动器按自己所在位置去推../lib/amd64/jvm.cfg目录对不上就报这个错。解决where java看顺序把自己那份前置。实在不想动 PATH就用全路径调用D:\tools\jre1.8.0_202\bin\java.exe -version先确认包本身没问题再解决路径优先级。二、java.lang.UnsupportedClassVersionError: ... has been compiled by a more recent version现象是跑 jar 时报类版本不支持数字形如 52.0 / 55.0 / 61.0。原因jar 是用更高的 JDK 编的运行时的 JRE 版本低。类文件版本号 52 对应 855 对应 1161 对应 17。JRE 8 只认到 52。这不是配置问题是硬性不兼容任何环境变量都救不了。解决要么用对应版本的 JRE 跑要么让打包方用-source 8 -target 8重新编。要注意仅仅加-source/-target还不够得同时保证编译时的基础类库版本匹配否则可能编过却运行时报NoSuchMethodError。最稳的是用对应版本的 JDK 编。三、javax.net.ssl.SSLHandshakeException: PKIX path building failed现象是访问内网 HTTPS 接口失败本机浏览器打开同样的地址却是正常的。原因浏览器有系统的证书信任链JRE 只认自己那份lib/security/cacerts内网自建 CA 的证书不在里面。解决用包里自带的 keytool 导入注意-alias别和已有条目重名# 导入内网 CA 证书-file 指向 .cer/.crt 文件 keytool -importcert -trustcacerts -alias intranet-ca \ -file /path/to/ca.crt \ -keystore /opt/jre1.8.0_202/lib/security/cacerts \ -storepass changeit -noprompt # 确认导入成功 keytool -list -keystore /opt/jre1.8.0_202/lib/security/cacerts \ -storepass changeit | grep -i intranet-ca如果 JRE 目录是只读的别硬改把 cacerts 拷出来改完用-Djavax.net.ssl.trustStore/path/cacerts指过去。这条要写进启动参数别忘了。四、日志中文乱码或者时间戳整体差 8 小时现象日志文件里中文变成问号或者方块或者明明是下午三点的时间戳写成早上七点。原因有两个独立来源。乱码是file.encoding和实际文件编码不一致1.8 在中文系统上默认 GBK你的日志框架按 UTF-8 写控制台按 GBK 解必然乱。时间差 8 小时是时区问题容器基础镜像默认 UTCJVM 跟着走。解决启动参数里同时加-Dfile.encodingUTF-8 -Duser.timezoneAsia/Shanghai。注意file.encoding必须在 JVM 启动时指定程序跑起来之后再改系统属性是无效的因为默认字符集在启动阶段就被缓存了。五、控制台莫名多出一行Picked up JAVA_TOOL_OPTIONS: ...现象每次启动都打印这行提示而且行为和你写的启动参数不一致比如明明没设-Xmx堆大小却不对。原因机器上存在JAVA_TOOL_OPTIONS或_JAVA_OPTIONS环境变量它们会被 JVM 自动读取并合并进启动参数优先级还常常高于命令行。这在共享构建机或者被前人折腾过的服务器上特别常见。解决echo %JAVA_TOOL_OPTIONS%和echo %_JAVA_OPTIONS%各看一遍有就清掉。清不掉比如是系统级设置动不了的话用-XX:-PrintVMOptions之类压不住正确做法是在启动脚本里显式set JAVA_TOOL_OPTIONS置空把它盖掉。6. 把 JRE 1.8 做成可交付件裁剪清单与上线前自检交付次数多了会发现原样拷一个 190MB 左右的 JRE 目录客户那边经常嫌大尤其是在带宽受限的内网分发。1.8 没有 jlink那是 9 之后才有的事能做的是按目录做手工裁剪配合一份自检脚本把它变成一个可复现的交付物。先明确哪些能删。纯后端服务用不到图形界面lib/fonts整个目录可以去掉bin/javaws那一套是给浏览器插件和 Web Start 用的早就没人用了bin/jcontrol是部署控制台纯文本环境里完全多余jjs和lib/ext/nashorn.jar是脚本引擎后端项目基本不碰。这几项加起来通常能省下 40MB 以上对镜像分层和分发都有意义。反过来lib/rt.jar、lib/charsets.jar、lib/security/cacerts、lib/ext/localedata.jar这几样不要动。charsets 删了某些编码转换会抛异常localedata 删了日期格式化的 Locale 会退化这些都属于删的时候没感觉出问题查三天的类型。裁剪脚本我一般写成这样#!/usr/bin/env bash # trim-jre.sh —— 在源 JRE 副本上裁剪绝不直接改原始包 set -euo pipefail SRC/opt/jre1.8.0_202 DST/opt/jre-min rm -rf $DST cp -a $SRC $DST # 无 GUI 场景字体和浏览器插件运行时用不到 rm -rf $DST/lib/fonts rm -f $DST/bin/javaws $DST/bin/javaws.exe # Nashorn 脚本引擎纯后端服务不加载 rm -f $DST/bin/jjs $DST/bin/jjs.exe $DST/lib/ext/nashorn.jar # 部署控制台 rm -f $DST/bin/jcontrol $DST/bin/jcontrol.exe # 打印前后体积对比方便评估收益 du -sh $SRC $DSTset -euo pipefail是必须的-e让任何一步失败立刻停避免裁出一个半成品还被打包-u让引用未定义变量时报错防止$SRC拼错变成空路径导致rm -rf /pipefail让管道里的失败也能被捕获。cp -a保留权限位不然 Linux 上bin下的可执行位全丢。裁完之后不能直接发得跑一遍自检。我把检查项固化成脚本每次交付前必跑#!/usr/bin/env bash # check-jre.sh —— 上线前自检任何一个关键文件缺失都以非零码退出 set -u JRE${1:?用法: check-jre.sh /path/to/jre} fail0 # 关键路径清单按启动链路顺序排列 for f in bin/java lib/rt.jar lib/charsets.jar lib/security/cacerts; do if [ ! -e $JRE/$f ]; then echo 缺失: $f fail1 fi done # 能起来只是及格属性对不对才是关键 $JRE/bin/java -version 21 | head -n 3 $JRE/bin/java -XshowSettings:properties -version 21 \ | grep -E java.home|os.arch|file.encoding || fail1 exit $fail这套脚本的价值不在代码本身在于它把我觉得应该没问题变成了跑过了退出码是 0。交付前少跑一次代价往往是现场返工。裁剪项省下体积风险建议lib/fonts约 20MB图形界面中文变方块纯后端可删bin/javaws*约 1MBWeb Start 启动失败可删bin/jjs nashorn.jar约 10MB内嵌 JS 脚本无法执行确认代码里没有脚本引擎调用后删bin/jcontrol*约 1MB部署控制台不可用可删lib/ext/localedata.jar约 5MB部分 Locale 格式化退化不建议删lib/security/cacerts约 100KBHTTPS 全部失败绝对不能删最后提醒一句关于版本号的事不要把1.8当成都一样。不同小版本之间容器内存感知、TLS 默认协议、证书库内容都有差异同一个 jar 在 u102 上跑得好在 u202 上因为 TLS 版本协商失败而起不来这种案例我遇过。交付时把完整小版本号写进交付文档别只写 jre1.8。从那以后我每次交付免安装 JRE不管客户多急都强制走一遍自检脚本并且要求对方在他们自己的机器上再跑一遍——环境不一样我这台过了不代表他那台能过。希望帮到你。本文还有配套的精品资源点击获取