最近在容器环境中,发现在 Java 进程是 1 号进程的情况下,无法使用 arthas。
提示 AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread。具体操作和报错如下:
# java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.5.6
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 1 com.alibabacloud.mse.demo.ZuulApplication
1
[INFO] arthas home: /home/admin/.opt/ArmsAgent/arthas
[INFO] Try to attach process 1
[ERROR] Start arthas failed, exception stack trace:
com.sun.tools.attach.AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread
at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:86)
at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78)
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250)
at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:117)
at com.taobao.arthas.core.Arthas.<init>(Arthas.java:27)
at com.taobao.arthas.core.Arthas.main(Arthas.java:166)
[INFO] Attach process 1 success.
之前也遇到过,总是调整了下镜像,让 Java 进程不是 1 号进程就可以了。但这个不是长久之计,还是要抽时间看下这个问题。
复现问题
我们创建如下项目,来复现这个问题:
public class Main {
public static void main(String args[]) throws Exception {
while (true) {
System.out.println("hello!");
Thread.sleep(30 * 1000);
}
}
}
FROM openjdk:8u212-jdk-alpine
COPY ./ /app
WORKDIR /app/src/main/java/
RUN javac Main.java
CMD ["java", "Main"]
然后正常启动应用,并尝试用 arthas,或者 jstack:
$ # 构建镜像
$ docker build . -t example-attach
$ # 启动容器
$ docker run --name example-attach --rm example-attach
$ # 在另一个终端进入容器,执行jstack
$ docker exec -it example-attach sh
/app/src/main/java # jstack 1
1: Unable to get pid of LinuxThreads manager thread
成功复现问题!接下来开始分析。
正常的 attach 流程是什么样子的?
如下是在排查问题中,梳理出来的 jvm Attach 流程:
- 查找 /tmp/.java_pid${pid} 这个 unix socket,如果存在则检查权限,然后建立连接。
- 如果不存在则先创建 /proc/${pid}/cwd/.attach_pid${pid},开始通知 jvm 线程。
- 首先判断是不是 LinuxThread如果是 LinuxThread则找到 Linu