☰
Arthas启动找不到Java进程?五步排查法与实战解析
2026/10/1 1:16:59 网站建设 项目流程

1. 问题现象:Arthas 启动时的经典"翻车"现场

先说说我自己第一次遇到这个问题的经历。当时是在一台 CentOS 7 的测试服务器上排查一个 Spring Boot 服务的内存异常问题,习惯性敲下java -jar arthas-boot.jar,结果控制台直接给我来了一句:

[INFO] Can not find java process. Try to pass <pid> in command line.

我那时候还愣了一下:明明ps -ef | grep java能看到进程还活着,怎么 Arthas 会找不到?后来试了jps,也提示process information unavailable。又试了加 PID 直接 attach 的方式,结果报Unable to open socket file。那一整个下午我都在跟这个报错较劲,后来陆陆续续在不同环境里又碰到过几次,才算把这个问题彻底摸透。

这篇文章就围绕这个场景展开,把 Arthas 启动时找不到 Java 进程的各种原因、判断思路、解决手段一次性讲清楚。不管你是用 Arthas 做日常排查的 Java 开发,还是负责线上环境维护的运维或 SRE,只要你需要在服务器上面对 JVM 应用,这篇文章都能帮你少踩几个坑。

顺便说一句:Arthas 这个工具本身非常好用,阿里开源的 Java 诊断利器,不修改代码、不重启服务就能在线排查问题,包括方法调用追踪、热更新、内存快照分析等。但工具再好,如果第一步连进程都 attach 不上去,后面全是白搭。所以把"启动阶段"的坑填平,是高效使用 Arthas 的前提。

2. 核心原理:Arthas 到底是怎么"找到" Java 进程的

要解决一个问题,先得理解背后的机制。Arthas 启动时并不是漫无目的地去全盘扫描进程,它的进程发现机制其实分成了好几层,每一层都有各自的前提条件和短板。搞清楚这些,你才知道报错信息到底在告诉你什么。

2.1 报错信息的真实含义

"Can not find java process"这句话很容易误导人,它并不是说你的 Java 进程不存在,而是说 Arthas 在它预设的查找逻辑里没有找到"符合条件"的进程。这就像你让朋友帮你在书架上找一本书,朋友说"没找到",很可能不是书不在,而是书放在了别的书架上,或者书的封面上没有你描述的特征。

Arthas 的查找逻辑大致是:通过调用ps命令枚举系统进程,筛选出名字里包含java的进程,再进一步做 attach 操作。如果筛选结果为空,或者筛选出的进程在 attach 时失败,它就会报告这个经典的错误。

所以,当你看到这个报错时,脑子里要立刻浮现出三个待排查方向:进程本身是否存在、进程是否被正确识别、attach 动作是否被允许。下面拆开细说。

2.2 Arthas 获取进程列表的两条路径

Arthas 获取进程列表的方式,本质上依赖 JVM 的 Attach 机制。它先通过系统级命令枚举所有进程,再用 Java 自带的VirtualMachine.list()方法来获取可 attach 的 JVM 列表。这两条路分别对应不同的排查方向:

第一,操作系统层面。Arthas 会执行类似于ps -ef | grep java的操作,拿到机器上所有命令行里包含java的 PID,然后展示在启动界面上。如果这个环节出问题,通常表现为"列表里什么都没有"。

第二,JVM 层面。Java 的 Attach 机制要求目标 JVM 在启动时创建临时文件目录(默认是/tmp/hsperfdata_<用户名>/),里面存放 perf data 文件。Arthas 通过VirtualMachine.list()可以拿到这些 JVM 的实例信息。如果这个目录不存在,或者 Arthas 进程没有权限读取,就会出现"能看到进程但 attach 失败"的诡异情况。

这里有个很容易被忽略的点:Arthas 启动后输入的序号,其实就是 JVM 实例的 PID。也就是说,Arthas 把系统进程列表和 JVM 实例列表做了比对,只有同时出现在两个列表里的进程,才会被展示出来供你选择。

2.3 导致"找不到"的五类典型原因

根据我自己的实战经验,以及身边同事踩过的坑,Arthas 启动时无法获取 Java 进程的原因大体可以归为五类:

  • 当前用户权限不足,无法读取/tmp/hsperfdata_*目录或执行 attach 操作
  • Java 进程是别人启动的,运行用户和 Arthas 启动用户不一致
  • 目标 JVM 是容器内的进程,宿主机上执行 Arthas 时看不到完整信息
  • 目标进程不是标准 Java 进程,或者是被改名、被重定向了启动命令的进程
  • Arthas 自身的依赖问题,比如 fastjson 版本冲突导致启动流程中断

后面的章节我会针对每一类原因给出具体的排查命令和解决方案。但先记住一个最重要的思路:不要只盯着 Arthas 的报错信息本身,要回到操作系统和 JVM 的层面去验证进程的真实状态。

3. 动手排查:我从实际踩坑中总结的五步确认法

这一部分是最实用的内容。我把自己多次排查这个问题的流程整理成了一套标准化的步骤,每遇到"Arthas 找不到进程",我就按这个顺序来,基本上五分钟内能锁定问题根因。

3.1 第一步:确认 Java 进程到底还活着没有

很基础但绝不废话的一步。不要想当然地认为服务还在就跑着,很多情况下服务进程早就崩了,只是你没注意到。而且要注意:jar包部署的应用、java -version进程、IDEA 里的 JVM 进程,在ps里都叫java,得分辨清楚。

先在目标机器上执行:

jps -lv

这个命令会列出当前用户下所有 Java 进程的 PID 和启动参数(-l显示完整主类名,-v显示 JVM 参数)。如果输出为空,或者根本没有jps命令,说明 JDK 环境变量没配好,或者进程不是当前用户启动的。

接着再用系统命令交叉验证:

ps -ef | grep java | grep -v grep

如果ps能看到进程而jps看不到,恭喜你,问题大概率是用户权限或者 hsperfdata 目录权限导致的。如果ps都看不到,那说明进程确实不存在,问题变成了"服务为什么挂了",这就不在本文讨论了。

实操心得:我曾经遇到过一次很尴尬的情况,ps能看到好几个 java 进程,但我其实不知道哪个才是目标服务的 PID。后来靠jps -lv里 JVM 参数带的-Dspring.profiles.active=test才认出来。所以我的习惯是先跑jps -lv,看启动参数认进程,比单纯看 PID 靠谱得多。

3.2 第二步:验证 Attach 机制的"基础设施"是否正常

JVM 的 Attach 机制依赖/tmp/hsperfdata_<用户名>目录。当我们执行jps或者启动 Arthas 时,工具会去这个目录读取 JVM 的 perf data 文件。

可以手动检查一下:

ls -la /tmp/hsperfdata_*

正常情况下,你应该能看到一个或多个以用户名命名的目录,比如hsperfdata_root、hsperfdata_admin。目录里面是形如<PID>的文件,没有扩展名。这个文件其实就是目标 JVM 运行时创建的 shared memory 映射文件,Attach 机制靠它做进程间通信。

如果这个目录不存在、权限不足、或者被系统定期清理了,Arthas 就无法感知到对应的 JVM 实例。

ls -la /tmp/hsperfdata_admin/

输出类似这样:

total 0 drwxr-xr-x 2 admin admin 60 Mar 15 10:22 . drwxrwxrwt 8 root root 4096 Mar 15 10:22 .. -rw------- 1 admin admin 32768 Mar 15 10:22 23456

看到这个 PID 文件存在,说明 JVM 的 perf data 是正常的。如果这步正常但 Arthas 还是报错,那问题多半出在权限上,等下第三步会细说。

有一点要特别提醒:有些系统会配置systemd-tmpfiles-clean.timer定期清理/tmp目录,或者 Docker 容器里容器的/tmp被映射到临时文件系统,重启后目录就没了。我遇到过一次线上事故,就是因为清理任务把旧的 hsperfdata 目录删了,所有 Java 进程在那台机器上都无法被附加,Arthas 彻底没法用,只能重启应用来恢复。这类问题最棘手的就是"重启前查不到,重启后临时恢复了",隐蔽性极强。

3.3 第三步:检查当前用户和目标进程的"身份关系"

如果你的应用是 root 用户启动的,而你当前登录的是普通用户,直接在终端里执行java -jar arthas-boot.jar,大概率会失败。

原因很简单:Attach 机制要求发起 attach 的用户和目标 JVM 的用户一致。JVM 创建的 hsperfdata 文件权限是-rw-------,也就是说只有文件所有者才能读。普通用户去读 root 的 perf data 文件,直接 Permission denied。

解决办法有两种:

第一种,切换成目标进程的启动用户去执行 Arthas:

sudo su - admin java -jar arthas-boot.jar

或者直接以 root 身份执行(如果安全策略允许):

sudo java -jar arthas-boot.jar

第二种,使用--target-ip参数配合远程 attach(这个是企业版功能,不展开)。社区版的标准做法就是切换用户。

这里有个常见疑问:为什么ps -ef | grep java能看到进程,jps却看不到?这正是因为ps是系统级的命令,每个人都有权限读/proc下的进程列表;但jps依赖 hsperfdata,而普通用户读不了 root 的 hsperfdata。两者机制不同,所以才有这种"看得到但 attach 不了"的矛盾现象。

注意:如果你是在公司生产环境,千万别直接sudo执行不知名的 jar 工具。Arthas 虽然官方开源,但出于安全考虑,建议先在测试环境验证操作流程,再在线上执行。而且操作前最好确认一下这个 arthas-boot.jar 是从官方渠道下载的,哈希值核对一下再跑。

3.4 第四步:绕过自动检测,直接指定 PID

Arthas 启动时其实支持直接传 PID 参数,跳过自动检测进程列表的步骤:

java -jar arthas-boot.jar 23456

这里的23456是目标 Java 进程的 PID。这个方法更直接,但有一个前提:你必须知道准确的 PID,而且当前用户依然要有权限 attach。如果直接指定 PID 后仍然报错,写入日志的错误信息会更有针对性,比如:

  • java.io.IOException: Connection refused,通常是 attach socket 通信失败,多半是权限问题
  • com.sun.tools.attach.AttachNotSupportedException,说明目标进程不是标准 Java 进程,或者不是 HotSpot/OpenJ9 的 JVM
  • Unable to open socket file,说明 hsperfdata 里的 socket 文件不可读,一般是用户在切换(如su后未完整初始化)时造成的

有时候我们生产环境的 Java 进程是 root 用户起的,但是我会用一个低权限账号去执行 Arthas 排查,这时候就会非常纠结。其实还有一个比较隐蔽的操作:使用sudo -u root执行 Arthas。但要注意,sudo 时如果环境变量带了奇怪的 JAVA_HOME,也会影响启动结果。

实操心得:直接传 PID 是跳过"自动检测"环节最有效的手段。但如果你连 PID 都不清楚,可以先用下面的命令找到准确的 PID:

pgrep -f 'java.*myapp.jar'

这会返回所有命令行里匹配myapp.jar的进程 PID。多个实例会有多个 PID,注意甄别。

3.5 第五步:确认 Arthas 自身依赖是否完整

最后一步,如果前面所有操作都正常,但 Arthas 还是报错,那就得怀疑 Arthas 这个 jar 本身是否健康了。

Arthas 在启动过程中会加载自身依赖的类库,尤其是 fastjson。如果类路径里存在老版本或冲突版本的 fastjson,可能造成启动过程异常中断,表现看起来就像是"没找到进程"。

常见的症状是启动日志里出现:

Exception in thread "main" com.alibaba.fastjson.JSONException

或者干脆在打印进程列表之前就抛异常。遇到这类情况,建议去 Arthas 的 GitHub Releases 页重新下载最新版arthas-boot.jar,官方地址是https://github.com/alibaba/arthas/releases,下载后对比一下 SHA-256 再使用。

你也可以用另一种方式安装 Arthas 到本地:如果你用 Homebrew(macOS / Linux 环境),可以执行:

brew install arthas

brew 会帮您管理好版本、依赖和启动脚本,省去手动下载 jar 的麻烦。

补充一点:Arthas 需要 JDK 8 及以上版本才能运行。如果你机器上默认的java是 JRE(没有tools.jar和 attach 相关的类),也会导致无法 attach。这一步很关键:执行java -version确认版本,执行which javac确认是 JDK 而非纯 JRE。纯 JRE 环境下 Arthas 是没法工作的。

4. 真实场景专项分析:不同环境下的表现和处理方式

同一个问题,在不同环境里的"长相"差异非常大。这一节我挑四个典型场景,把每个场景下的关键特征和应对方法单独拎出来讲。

4.1 场景一:本地 IDEA 启动的应用,Arthas 找不到进程

很多人在本地开发时也会用 Arthas,终端里执行java -jar arthas-boot.jar,结果发现列表里空空的,自己的 Spring Boot 应用没有被列出来。

原因通常不是权限,而是 IDEA 的 Launcher 机制。IDEA 启动应用时,默认使用com.intellij.rt.execution.application.AppMainV2来代理执行 main 方法,进程名虽然是 java,但主类和启动参数不太一样,Arthas 在某些版本下会识别不出来。

解决办法很简单:给 IDEA 的 JVM 启动参数里加上-Djava.rmi.server.hostname=127.0.0.1之类的参数通常没用,真正有效的是在 IDEA 中配置 JVM 参数时显式添加:

-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

等等,这个配置是让 JMX 可被外部工具连接的,并不直接影响 Arthas 的 attach。实际上 Arthas 查找进程走的是VirtualMachine.list(),不依赖 JMX。IDEA 场景下更靠谱的做法是:用jps -lv找到 PID,然后直接执行java -jar arthas-boot.jar <PID>来指定。

实操心得:我在本地调试时,已经形成固定流程——先用jps找到 PID,再直接用java -jar ~/arthas/arthas-boot.jar <PID>去 attach。这样最省事,不用等 Arthas 慢慢出列表。

4.2 场景二:Linux 服务器上通过 jar 包部署的服务

生产环境最常见的部署方式就是nohup java -jar myapp.jar > app.log 2>&1 &。这种情况下,进程的启动用户通常是你登录的用户,理论上不会出现权限问题。

但如果你用systemd管理服务,配置文件里指定了User=xxx,那进程就是以 xxx 用户运行,你得切到 xxx 用户再执行 Arthas。

我在多个项目里都见过调度脚本里写明用su -s /bin/bash nobody -c 'java -jar /opt/app.jar'来启动进程的。这种场景下进程属于nobody,你拿自己的账号执行 Arthas,同样找不到。解决方式还是那句老话:sudo -u nobody java -jar arthas-boot.jar。

也可以通过jps -lv来查看每个启动参数里的关键信息,比如:

jps -lv | grep app.jar

这样能确认 PID、确认启动用户,还能看到-Dspring.profiles.active这类环境配置。如果是服务部署在/opt/下,可能存在 SELinux 限制导致 attach 被拒绝。上述命令里如果不确定,可以附加-q查 PID,再用ps -o pid,user,cmd -p <PID>查归属用户和完整命令行。

注意:这类服务器上多半有多个 Java 应用,直接执行 Arthas 会列出全部进程,这时候别选错 PID,选错了 attach 到别人的服务上,虽然一般不会造成破坏,但操作目标是错的,排查结果毫无意义。

4.3 场景三:Docker 容器里的 Java 服务(最容易踩坑)

现在微服务上容器是主流,Docker 容器里的 Java 进程让很多人栽过跟头。

如果你在宿主机上直接执行java -jar arthas-boot.jar,大概率是找不到容器里的 Java 进程的。原因有两个层面:

第一,容器有自己独立的 PID namespace。宿主机上的 PID 和容器内的 PID 不是一回事,你在宿主机上看到的进程号,跟容器内ps看到的进程号可能完全不同。Arthas 的 attach 机制依赖的是宿主机级别的/proc和/tmp/hsperfdata目录,而容器内的路径对宿主机来说可能不可见。

第二,hsperfdata 文件的权限单独在容器内部管理。容器内启动 Java 进程的用户(比如java用户,UID 1000)和宿主机上跑 Arthas 的用户不一致,即使能读/proc,也读不了/tmp/hsperfdata_java。

正确做法是进入容器内部执行 Arthas:

docker exec -it <container_id> /bin/bash java -jar arthas-boot.jar

前提是容器里装了 JDK,而且arthas-boot.jar在容器里能访问到。如果容器很精简,连jps都没有,那还是先把 JDK 装进去或者复制一个静态编译的 JDK 进去。

避坑技巧:有些容器是FROM openjdk:8-jre-alpine这类精简镜像,里面连/tmp/hsperfdata都没有或者被只读挂载了。遇到这种情况,我一般直接在 Dockerfile 里显式创建目录并授权:

RUN mkdir -p /tmp/hsperfdata_java && chmod 777 /tmp/hsperfdata_java

或者在启动命令中动态加-XX:-UsePerfData这个参数(这个参数会关闭 perf data 的生成,但问题也会随之消失:没有了 perf data 文件,attach 时连路径都找不到)。总之,生产环境中如果需要 Arthas 排查,足够重视容器镜像的 perfdata 环境是很重要的。

关于 K8s 环境多说一句:如果你在 K8s 里跑应用,首选方式是kubectl exec -it <pod> -- java -jar arthas-boot.jar,直接进 Pod 里操作。如果是 InitContainer 或 sidecar 模式,共享进程命名空间需要注意 PID 映射。其实在 K8s 集群中,更合理的做法是给目标项目集成 Arthas Tunnel Server 或使用 Kubernetes 插件,但这个主题比较大,这里先不展开。大家记住最核心的一条:Arthas 要和目标 JVM 在同一个可通信的进程命名空间里,且用户权限匹配。

4.4 场景四:多 JVM 实例和自定义进程名的特殊情况

如果你机器上有多个 Java 应用,或者其他中间件(如 Kafka、ZooKeeper)也以 Java 进程运行,那么 Arthas 的进程列表会非常长,识别起来非常烦。

jps的优势在这里就体现出来了,它不会列出命令行里不含java的进程(严格来说,jps 本身也只枚举 JVM 实例,不含资源占用高的非 JVM 进程)。但如果你用ps | grep java去筛,可能会把 CI 工具的守护进程(比如 Jenkins 是个 Java 应用)、监控 agent 也一起筛出来。

还有一种特殊情况:有些团队为了隐藏进程信息或者做安全加固,会把java二进制改名,比如叫jre8、myapp-runtime。这种情况下ps | grep java根本找不到,Arthas 自动检测自然失效。解决办法是先通过ps -ef找到目标进程的真实 PID,然后用ls -l /proc/<PID>/exe看一下实际二进制路径,确认它确定是 Java 进程后,再通过java -jar arthas-boot.jar <PID>强制 attach。

ls -l /proc/23456/exe

输出类似.../jre8/bin/java,说明它确实是改名后的 JVM。传 PID 参数的方案是最稳的。

5. 常见问题与排查技巧速查表

按上面那套五步法,绝大多数问题都能解决。但如果还是卡住,下面这张速查表可以作为补充,结合错误信息和环境特征快速定位根因。

错误信息可能原因解决建议
Can not find java process. Try to pass <pid> in command line.无法枚举到符合条件的 JVM 实例确认jps和jps -lv输出,按五步法逐层排查
process information unavailablehsperfdata 目录无法访问,或当前用户不是目标进程启动用户切换用户重试;修复/tmp/hsperfdata_*权限
Unable to open socket fileattach 所需的 socket 文件缺失或不可读检查/tmp/hsperfdata_*/目录权限;避免在不同用户间切换,必要时重启应用恢复
AttachNotSupportedException目标 JVM 不是标准 HotSpot JVM,或 Java 版本低于 8确认 JDK 类型与版本,替换为兼容的 JVM
Address already in useArthas listen 端口被占用换端口启动:java -jar arthas-boot.jar --telnet-port 9999 --http-port 8563
fastjson.JSONExceptionArthas 依赖的 fastjson 类冲突升级 Arthas 版本或切换安装方式(如 brew/官方脚本)

另外再补充几个排查思路:

  • 如果你用top或htop看到 CPU 占用异常进程,但jps里没有它,先判断它是否真的是 JVM 进程。可以用/proc/<PID>/status看进程名和命令行,排除自定义二进制或改名 JVM。
  • 如果应用部署在 Kubernetes 中,并且有多个副本,注意 Pod 被调度到不同节点的问题。你要排查哪个 Pod,就要进到对应的节点或直接用kubectl exec进入 Pod,别在错误的机器上白忙活。
  • 遇到"某台服务器上所有 Java 进程都 attach 不了"的情况,优先怀疑/tmp目录或 hsperfdata 目录下的文件被清理。遇到这种非常规情况,最干净的办法是重启受影响的应用,让 perf data 重新生成。
  • 如果线上不方便用jps,可以下载 jdk 的 bin 目录单独复制 jps 和 lib 进来,或者用cat /proc/stat查看进程信息,但更推荐直接在你的 CI/CD 流程里预留一个便携 JDK(用官方基础镜像的 jdk 版本能省很多事)。

6. 最后的个人经验总结

Arthas 启动找不到进程,十次里有八次是权限或用户身份问题,剩下两次是环境隔离(容器、改名进程、目录清理)造成的。这套问题并不是什么高深莫测的技术难题,但确实需要你在多个层面依次排查,按顺序排除才能最快定位。

我个人在实际操作中的习惯是:拿到一台新服务器,先执行jps -lv和ps -ef | grep java,两个命令的结果放一起对比,既能确认进程是否存在,又能顺便确认启动用户和 JVM 参数。然后再动手执行 Arthas。这三步走完,90% 的问题就已经有答案了。剩下 10% 如果还不行,再回头看 hsperfdata 目录和 Arthas 依赖,基本没有解不掉的。

最后再分享一个小技巧:Arthas 启动时如果你有时间,可以把arthas-boot.jar放到固定的目录,比如~/tools/arthas/,同时配置一个 shell alias:

alias arthas='java -jar ~/tools/arthas/arthas-boot.jar'

这样每天排查问题时敲命令都少几个键,省下来的时间虽然不多,但关键时刻那几秒可能就是服务恢复的黄金时间。

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

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

立即咨询