尧图精选

Arthas找不到Java进程?排查思路与实战方案

🕒 发布时间:2026/10/1 21:54:02 📁 来源:尧图网络
Arthas 是我线上排查 Java 问题最常用的工具没有之一。不管是 CPU 飙高、线程卡死还是接口偶发超时只要把java -jar arthas-boot.jar跑起来基本都能在现场找到线索。但恰恰是这一步很多朋友第一次执行就翻车屏幕上甩出一句Can not find java process. Try to pass pid directly.然后进程退出留下你对着终端发呆。这个“Arthas 启动时无法获取 java 进程”的问题看着简单背后涉及的坑却不少用户权限不一致、容器 PID 命名空间隔离、JDK 版本兼容、端口占用、/tmp目录异常等等。我这些年踩过不少类似的坑也帮同事排查过很多次今天就把完整的排查思路和实操方案整理出来希望能帮你少走弯路。1. 问题现象与根因速览1.1 你的报错是哪一种“无法获取 java 进程”并不是某一条固定的报错而是一类现象的总称。我实际遇到的至少有三种不同表现先对照一下你属于哪种。第一种最常见就是开头提到的那句Can not find java process. Try to pass pid directly.。这通常意味着 Arthas 启动脚本在自动扫描本机 Java 进程时一个都没扫到或者扫到了一批但都被过滤掉了。这个报错在没加-p参数时最容易出现Arthas 会去识别当前环境里的 JVM识别失败就直接退出。第二种是connect to target vm failed。这个报错说明 Arthas 已经找到了目标进程但 attach 连接被拒绝或者建立连接的过程中出现了异常。常见原因包括目标 JVM 关闭了 attach 机制、当前用户没有权限、JVM 正处于异常状态等。这种报错比“找不到进程”更进一步说明问题出在 attach 链路。第三种不是启动阶段直接报错而是 ArThas 启动成功了但后续无法访问控制台比如 telnet 3658 端口连不上或者 HTTP 端口访问不了。这时候报错信息往往是Connection refused或者timeout容易被误判为“启动失败”实际是端口被占用、防火墙拦截、网络命名空间不通等问题。这三种现象背后对应完全不同的排查路径。你如果只看“无法获取 java 进程”这几个字就照着网上的教程一顿操作很可能用修 A 问题的方案去搞 B 问题最后越弄越乱。1.2 核心机制Arthas 是怎么拿到 Java 进程的要理解报错得先知道 Arthas 启动时内部做了哪些事。Arthas 的启动脚本as.sh或者arthas-boot.jar里有一段自动扫描逻辑如果你没有用-p参数指定 PID它会遍历当前机器上所有进程筛选出可识别的 Java 进程然后列一个带序号的菜单让你选择。如果扫描结果为空就会直接报 Can not find java process。这一层扫描依赖的是 Linux 下的/proc文件系统以及 JVM 在/tmp/hsperfdata_user/目录下生成的性能数据文件。Arthas 会读取/proc下的进程列表找到启动文件名或命令行里包含java的进程再判断能否作为 attach 目标。如果/proc不可读、Arthas 运行用户和目标 JVM 用户不一致、或者目标进程的启动名被改掉扫描结果就会异常。确认 attach 目标之后Arthas 会通过 JDK 自带的com.sun.tools.attachAPI 连接到目标 JVM。这个连接是否成功又受到用户权限、PTTY、容器 PID 命名空间、/tmp目录可写性、JVM 参数-XX:DisableAttachMechanism、JDK 模块访问限制等多重因素影响。所以“无法获取 java 进程”这句话其实是“进程发现失败”和“attach 建立失败”两层问题的统称排查时务必要先分清楚是哪一层。2. 排查思路先确认进程真的存在且可 attach2.1 用 jps 和 ps 验证进程状态拿到“无法获取 java 进程”的报错时我的第一步从来不是去看 Arthas 的配置而是先自己确认目标 Java 进程到底还在不在。这听起来很基础但很多人真的会跳过这一步直接怀疑 Arthas 坏了。我建议两条命令一起执行ps -ef | grep java和jps -l。前一条命令查看的是操作系统视角下的进程列表后一条查看的是 JVM 视角下的进程列表。两个命令的结果一对照就能判断问题在操作系统层还是在 JVM 发现层。举个例子我遇到过一种情况项目跑在 systemd 服务里启动脚本把进程名改成了javaapplicationps -ef能清楚看到这个进程但jps -l的输出却是空的。原因是这个 JVM 启动时发生了一些异常导致/tmp/hsperfdata_目录下没有生成对应文件或者生成后权限不对。Arthas 自动扫描是依赖jps同类的机制来发现进程的所以jps看不到Arthas 自然也就看不到。反过来jps能看到进程也不代表 Arthas 一定能 attach。jps只是读取进程的存活信息而 attach 需要与 JVM 建立 socket 连接这里面还有权限和环境的制约。所以我会把ps -ef和jps -l作为第一道筛子先把“进程是否存在”和“JVM 是否可发现”这两个状态搞清楚。2.2 三种典型场景导致 jps 看不到进程如果ps -ef | grep java能看到进程但jps -l看不到通常跳出下面三种场景。第一种是用户不一致。jps和 Arthas 运行在普通用户下但 Java 进程是 root 启动的。此时/tmp/hsperfdata_root目录只有 root 能读普通用户执行jps -l自然什么都看不到。这种情况在服务器上非常常见运维同学用一个部署账号管理服务但某些中间件或脚本用 root 拉起 Java 进程诊断的时候就发现工具“瞎了”。第二种是容器环境。你在宿主机上执行jps看到的是宿主机 PID 命名空间里的进程。容器里运行的 Java 服务在宿主机上也能看到进程但它的/tmp目录和hsperfdata文件是隔离在容器命名空间里的宿主机上的jps往往读不到容器内 JVM 的信息输出为空非常正常。第三种是jps自身的坑。比如 Linux 上/tmp目录被挂载为 noexec 或只读jps创建临时 socket 失败或者 JDK 版本较老对某些进程名兼容性不好再比如进程正处于大量 GC 或假死状态也可能导致jps超时或读取不到。我自己的排查习惯是先ps -ef | grep java看进程在不在再jps -l看 JVM 能不能被发现再用ls -l /proc/pid/cwd看当前用户是否具备访问权限。这三步走完八成以上问题都能定位到具体环节。3. 常见原因逐个击破3.1 权限问题你不是我我不能让你进来Arthas attach 目标 JVM 时要求 Arthas 的运行用户和 JVM 的启动用户一致这是一条安全规则。如果服务是以root用户启动的而你用deploy账号执行java -jar arthas-boot.jarArthas 可能在扫描阶段看到进程但 attach 阶段会被拒绝报错connect to target vm failed或Permission denied。解决方式不复杂切换到目标进程相同的用户再启动 Arthas。比如su - deploy -c java -jar arthas-boot.jar或者用sudo提权执行。我个人更倾向于用服务账号而不是 root 去执行 Arthas。因为你用 root 虽然能 attach 任何进程但操作风险大而且在审计上不好看。而且用 root 成功掩盖了潜在的权限配置问题下次换回普通用户又傻眼。确认当前 Java 进程属于哪个用户可以用ps -o user,pid,cmd -p pid如果进程是你自己起的权限一般没问题。如果是在别人管理的机器上先和对方确认账号沟通成本不高但能少走很多弯路。3.2 容器环境世界被分成两个 PID 空间容器环境导致的 attach 问题是近两年我遇到最多的一类。核心原因在于 PID 命名空间隔离。Arthas 运行时要 attach 目标 JVM两个进程必须处于同一个 PID 命名空间或者至少拥有跨命名空间 attach 的权限。你在宿主机上直接运行 Arthas看到的是宿主机的进程表。容器内的 Java 进程在宿主机看来也只是一个独立的普通进程虽然能看到但由于命名空间隔离“够不着”它内部的 attach 文件。即使你手动指定宿主机的 PIDattach 也常常失败因为 JVM 的 attach 机制依赖/tmp/.java_pidpid文件和/proc/pid目录这些在容器内外并不是完全互通的。最稳妥的方案是如果 Java 进程在容器内就把 Arthas 的启动命令通过docker exec或kubectl exec送进同一个容器里执行。比如kubectl exec -it pod-name -- bash java -jar arthas-boot.jar -p 1前提是容器里有java命令且有足够的 shell 和工具。很多精简镜像没有 bash 也没有 jps那就得先把 Arthas 包拷贝进去再用容器里仅有的工具运行。还有一种更干净的方案是给 Pod 加一个 sidecar 容器专门放 Arthas 和诊断工具与主业务容器共享 PID 和网络命名空间然后进入 sidecar 操作。这个方案对生产环境侵入性小也方便统一管理。3.3 JDK 版本与 Arthas 版本不兼容Arthas 对 JDK 版本相当敏感。你用 JDK 6 跑老项目很多新版本 Arthas 根本不支持因为com.sun.tools.attachAPI 在新版本里变化比较大。反过来如果你的项目已经跑在 JDK 17 及以上Arthas 启动时可能因为模块系统访问限制报Unable to access com.sun.tools.attach或者IllegalAccessError之类的错。遇到这种情况先确认当前 Arthas 版本对 JDK 的支持情况。Arthas 官方 README 里有兼容矩阵JDK 6 基本都支持但每个版本对新 JDK 的适配进度不同。我自己的经验是尽量把 Arthas 保持在较新的稳定版如果项目偏偏很老就固定一个历史版本别随意升级。为了追一个 bug 升级 Arthas结果发现 attach 不上了得不偿失。还有一个隐蔽的坑Arthas 启动脚本as.sh使用的java命令可能来自 PATH 中的第一个 Java而这个 Java 的版本未必和目标 JVM 一致。比如目标 JVM 是 JDK 11但as.sh用的是 JDK 8attach 时可能因为版本不匹配报NoSuchMethodError或者UnsupportedClassVersionError。解决办法是显式设置JAVA_HOME环境变量让 Arthas 使用与目标 JVM 一致的 JDK。3.4 系统架构与 Linux 发行版差异Arthas 本身是 Java 工具跨平台能力很强但启动脚本里涉及一些 native 操作比如解析/proc、执行ptrace系统调用这些会受到系统架构和内核权限影响。比如在 Mac M1 上如果用的是 ARM 架构的 JDKArthas 老版本可能没有为 ARM 做好适配启动时报错。Linux 上 SELinux 或 AppArmor 也可能拦截ptrace操作导致 attach 失败。遇到这类问题建议先看系统级日志。运行dmesg或journalctl -f观察是否有operation not permitted或 SELinux 拦截记录。如果是容器环境还要看有没有给容器加SYS_PTRACE权限。Docker 默认会放行部分 ptrace 操作但严格配置下可能被禁止。你可以用--cap-addSYS_PTRACE或者修改安全上下文来放开。另一个容易被忽略的点是/tmp目录的状态。Arthas attach 时需要写临时文件到/tmp如果/tmp被挂载为 noexec、大小写不敏感、或者空间满了attach 都会失败。我遇到过两次/tmp被临时文件占满导致 Arthas 启动失败的案例清理完空间后一切恢复正常。所以排查时顺手检查一下df -h /tmp和mount | grep /tmp成本极低却能排除一个潜在的雷区。3.5 端口冲突与 telnet 连接问题Arthas 启动成功后会开启两个端口telnet 端口默认 3658HTTP/WebSocket 端口默认 8563。如果这两个端口被占用Arthas 可能无法启动或者在启动后客户端连接不上。表现上和“无法获取进程”不同但很多人也会归到这个分类下反馈。检查端口占用用ss -lntp | grep 3658如果看到有进程监听可以换端口启动./as.sh -p 12345 --telnet-port 9999 --http-port 9998如果你在容器里使用 Arthas还要注意网络命名空间问题。从宿主机的telnet 127.0.0.1 3658访问容器内的端口默认是访问不通的除非你做了端口映射或使用 host 网络模式。Kubernetes 环境更复杂不能直接用 Pod IP 访问端口需要先kubectl port-forward或者进入 Pod 内部再访问。4. 实操手动指定 PID 启动 Arthas4.1 获取 PID 的几种正确姿势如果自动扫描一直不靠谱最直接的办法就是告诉 Arthas 目标进程的 PID。获取 PID 的方法有很多我用得最多的是这几种。jps -l的输出简洁能直接看到主类名jps -lps -ef | grep java能看到更详细的启动参数方便通过服务名或 jar 包名识别进程ps -ef | grep javapgrep -f也经常用特别适合脚本场景pgrep -f your-service-name在 Kubernetes 环境里先kubectl get pod拿到 Pod 名再kubectl exec进去执行jps。注意容器内的 PID 和宿主机看到的 PID 并不一致你在容器内拿到的 PID 只能在容器内使用。有一个容易踩的坑ps -ef看到的可能不止一个 Java 进程比如环境里有多个服务或中间件。建议通过启动参数里的-jar xxx.jar或-Dspring.profiles.active等关键字来精确识别。拿不准的时候可以用jcmd pid VM.version验证一下这个 PID 是不是 JVM 进程。4.2 一键启动并验证拿到 PID 以后启动 Arthas 就很简单了。脚本版用./as.sh -p 12345jar 包版用java -jar arthas-boot.jar --pid 12345如果你已经知道默认端口被占用可以在启动时指定新端口./as.sh -p 12345 --telnet-port 9999 --http-port 9998启动成功后控制台会输出类似The target process is 12345, arthas home is /tmp/arthas/...的信息然后进入交互式终端。此时输入help能看到所有命令我习惯先跑dashboard看一眼整体状态再根据问题用thread、trace、watch等命令定位。如果启动时想保留更详细的日志加一个-v参数./as.sh -p 12345 -v-v会输出更底层的信息对定位启动失败很有帮助。4.3 attach 失败时的回退方案如果指定 PID 后依然报错说明问题不在“进程发现”阶段而是“attach 建立”失败了。此时我建议先用 JDK 自带的jcmd验证一下 JVM 的 attach 通道是否正常jcmd 12345 VM.version如果jcmd能正常返回 JVM 版本信息说明 attach 机制是通的问题可能出在 Arthas 本身比如版本兼容。如果jcmd也报错那就要检查目标 JVM 是否设置了-XX:DisableAttachMechanism或者容器内是否缺失libattach.so以及当前用户对/tmp目录是否有写权限。有一种情况比较特殊目标 JVM 处于安全降级状态比如正在 Full GC 或者执行有损 dumpattach 请求可能暂时无响应。这时候不要急着杀进程等一会儿再试通常能恢复。如果 Java 进程本身已经假死jcmd也无响应那就只能另想办法比如通过 JMX 或者进程内日志排查了。5. 容器内 Arthas 的正确打开方式5.1 容器内 attach 宿主进程先想清楚命名空间很多人问“能不能在宿主机上直接诊断容器里的 Java 服务”这是个好问题但答案往往让人失望。虽然容器内进程在宿主机上也能看到但 attach 的底层机制依赖文件系统和 socket跨 PID 命名空间时会出现各种不一致。你在宿主机上jps能看到进程但 Arthas attach 时可能找不到目标或者连上了却无法正常加载 agent。所以最省心的方案是进容器再诊断。Docker 环境用docker exec -it container bashKubernetes 环境用kubectl exec -it pod -- bash进入容器后用ps -ef或jps -l找到进程再运行 Arthas。但很多基础镜像为了瘦身只有 JRE 没有 JDK连jps都没有。这种情况下你可以先把 Arthas 的包拷贝进容器前提是容器里有java命令。还有一个更轻量的方式用nsenter进入目标进程的 PID 命名空间然后在宿主机上执行 Arthas让它看到容器内的进程。这个命令对权限要求高一般需要 root 或 CAP_SYS_ADMIN操作起来比较繁琐不如直接进容器简单。5.2 用 sidecar 模式解决跨容器诊断问题如果业务容器太瘦连进去也跑不了 Arthas另一个方案是 sidecar。在 Kubernetes Pod 里可以给某个 Pod 增加一个调试容器与主业务容器共享网络命名空间和 PID 命名空间默认开启用shareProcessNamespace: true开启。这样一来sidecar 容器里的jps、ps能看到主容器的进程Arthas 也能 attach 到主容器的 JVM 上。这种模式的好处是诊断工具和业务进程解耦镜像可以独立构建调试工具的升级也不影响业务。适合在生产环境长期保留一套标准化的诊断入口。但 sidecar 会增加 Pod 的资源占用而且意味着修改 Deployment 配置需要走变更流程。我在团队内部推广过一次效果不错但一定要记得给 sidecar 设置资源 limit不然它疯起来会殃及主容器。5.3 容器镜像缺失关键依赖时的临时办法临时救急的场景往往是不能进容器也不能改配置只能在宿主机上想办法。可以先检查目标 Java 进程启动时的完整命令行如果进程在宿主机上可见并且/proc/pid/cmdline内容完整那至少可以用系统层面的工具观察它。比如pidstat看 CPU、内存上下文切换ss -tlnp看端口连接这些不依赖 JVM attach能拿到不少信息。如果必须拿到 JVM 内部信息可以尝试提前在 CI/CD 构建阶段把 JDK 的诊断工具打入镜像或者用 Arthas 官方提供的 Docker 镜像作为调试镜像通过docker run共享 PID namespace 后进入。总之临时方案都挺绕不如从一开始就为镜像预留诊断能力省得以后再遇到同样问题。6. 进阶排查从 attach 机制入手定位问题6.1 理解 attach 协议文件 信号如果你连续排查了好几次都搞不定那就得从底层理解 JVM attach 协议的实现。这个过程大致是attach 客户端先读取目标 JVM 在/tmp/hsperfdata_user/pid目录下生成的文件获得目标 JVM 的一些信息然后写一个.java_pidpid文件到目标工作目录再给目标进程发送 SIGQUIT 信号。JVM 收到信号后会启动 attach listener 线程和客户端建立 socket 连接之后就能进行 agent 加载、命令执行等操作。从这套机制就能解释很多诡异问题。比如jps看不到进程就是因为/tmp/hsperfdata_目录下的文件缺失或不可读attach 失败很多时候是写.java_pid文件没有权限或者/proc不可访问容器内 attach 不准则是 PID 空间隔离导致 socket 地址不一致。理解了底层机制你就能顺着链路逐步排查先检查/tmp目录再检查/proc挂载再检查信号是否被屏蔽再检查安全策略。比对着报错信息漫无目的地试要高效得多。6.2 使用 jcmd 和 jattach 做二分定位遇到 attach 失败时我习惯用二分法快速定位。先用jcmd pid VM.version验证 attach 链路如果能通过基本说明 JDK 本身没问题问题在 Arthas 层比如版本或参数。如果 jcmd 失败问题基本在下层比如权限、文件系统或 JVM 启动参数。如果想进一步确认可以尝试使用jattach它是一个纯 native 的 attach 工具不依赖 JDK 的 tools.jar反馈更底层。如果jattach能成功说明目标和系统环境支持 attach剩下就查 ArThas 自身的兼容性。如果jattach也失败基本可以断定是系统或 JVM 设置问题。在某些极端情况下可以用strace跟踪 attach 过程的系统调用。比如strace -f -e traceprocess,network java -jar arthas-boot.jar -p 12345观察日志里open、connect、kill等调用在哪一步报错能精确到是权限、文件缺失还是 socket 连接失败。不过strace在容器里通常需要SYS_PTRACE权限没有权限时可以尝试jcmd自带的-J-XX:TraceClassLoading等参数不过效果有限。6.3 用 Arthas 自带的诊断选项和日志Arthas 启动脚本本身提供了一些调试选项不要忽略。我最常用的是-v它会输出更详细的启动过程包括扫描到的进程列表、attach 的日志、agent 加载情况等。如果启动失败这些日志能直接指向问题。日志文件一般在/tmp/arthas.log或者~/logs/arthas.log里面有启动时的完整堆栈。我帮别人排查问题第一件事就是让他把这段日志发给我比描述“报错了”有用得多。Arthas 还支持一些环境变量比如ARTHAS_LOG_PATH可以改日志路径ARTHAS_OPTS可以传 JVM 参数给 Arthas 自身。在高版本 JDK 下遇到模块访问问题时可以试试设置export ARTHAS_OPTS--add-exportsjava.base/jdk.internal.vmALL-UNNAMED --add-exportsjava.base/jdk.internal.miscALL-UNNAMED再启动 Arthas。这个技巧能解决很多 JDK 17 下的启动问题。7. 避坑清单与实操总结7.1 常见问题速查表我把这几年遇到的 Arthas 启动时无法获取 java 进程的典型情况和解决方案整理成一张表建议先收藏再看。现象可能原因快速排查/解决Can not find java process. Try to pass pid directly.自动扫描失败进程不存在或不在同一环境用ps -ef | grep java确认进程指定-p启动jps -l为空但进程存在/tmp/hsperfdata_目录权限或用户不一致用同用户运行或sudo执行或进入容器执行connect to target vm failedattach 被禁用/权限不足/attach 库缺失用jcmd pid VM.version验证检查-XX:DisableAttachMechanism端口 3658/8563 无法访问端口冲突或防火墙限制ss -lntp查看占用指定--telnet-port换端口容器内 attach 失败PID 命名空间隔离/容器缺工具docker exec/kubectl exec进入容器运行或用 sidecarJDK 17 启动报模块错误模块系统访问限制升级 Arthas或设置ARTHAS_OPTS加--add-opens/--add-exportsattach 成功但客户端 connect 不了网络命名空间/防火墙/端口映射问题telnet 127.0.0.1 3658测试检查网络策略这张表基本覆盖了绝大多数“无法获取 java 进程”的现场情景。遇到问题先按表格做一次对照再决定下一步操作。7.2 我的几条实际操作心得最后聊几句个人经验可能对你在生产环境处理问题有帮助。第一上线前先做一次 Arthas 启动演练。很多团队只在故障时才想起 Arthas等到真要用却发现环境根本连不上。我建议在发布流程里加一个健康检查脚本判断jcmd能否 attach 到自己的服务能在早期就暴露权限或 JDK 配置问题。第二不要用 root 到处跑 Arthas。虽然 root 能解决权限问题但会让权限相关的问题被掩盖而且生产环境用 root 跑诊断工具安全审计里多少有点说不过去。用服务账号并且把账号和端口规范写进团队文档。第三学会用 Arthas 之外的诊断工具做交叉验证。jstack、jmap、jcmd都是 JDK 自带的Arthas 连不上时它们可以作为备用。反过来如果这些工具连不上说明问题在 JVM 本身优先检查进程状态和启动参数。第四把 Arthas 的日志积累起来。每次启动失败都保留当时的arthas.log、ps -ef输出、jps -l输出按日期归档。很多看着玄学的问题翻几次日志就能发现规律。我记得有次连续几天在固定时间点报“无法获取进程”后来发现是那个时刻有个定时任务会重启应用而 Arthas 的启动时机刚好撞上重启窗口。这种问题不结合时间线光看报错根本找不到答案。Arthas 启动失败这件事拆开看并不复杂核心就是进程发现和 attach 连接两步。理解了底层机制再配合一套有序的排查方法基本上都能在几分钟内定位到原因。下次再遇到“Arthas 启动时无法获取 java 进程”别急着重启服务也别一上来就改启动参数先按本文的顺序从确认进程开始逐步排除权限、容器、版本、端口这几个高发点。大多数时候问题都会在几步之内露出真面目。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →