问题描述:
本地idea里的一个简单java例子,debug停在图示语句,运行jconsole尝试连接该进程。反复提示连接失败
image.png 屏幕快照 2019-01-03 下午3.33.01.png
问题诊断:
- 搜索关键词“idea jconsole 本地连接失败”,查到的都是说要在jvm参数里增加:
-Djava.net.preferIPv4Stack=true
如下图所示增加后不生效:
image.png
- 尝试用jconsole连接idea的进程,可以成功:
抓出两个进程启动的参数分别如下:
【可以连接】
image.png
【不能连接】
image.png
发现其中不能连接的启动参数中有
-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:58329
这是debug模式运行时开放的端口,用于和jvm通信,获取jvm运行状态中的必要信息。
于是猜想,是否是debug模式不支持连接jconsole,随即将代码改成如下:
public class ReferenceTest {
public static void main(String[] args){
String b = new String("test");
while(true){
System.out.println(b);
}
}
}
运行,再从jconsole连接,成功:
image.png- 尝试把之前加的jvm参数都去掉,再执行,仍然可以连接成功。
结论
idea中debug模式运行停在断点时,jconsole不能连接该进程。与jvm参数之类的没有关系。
以上jvm参数在jconsole连接远程虚拟机进程时需要确保设置,才能正常连接。
com.sun.management.jmxremote.port=portNum
深入探究
- debug原理:
本质上debug原理是通过一种方式把jvm运行时的状态(变量值,当前运行行号,异常信息等等)传递回IDE进行显示。这种方式不能污染jvm运行时的数据,也就是需要在运行中途停得下来,又不会影响其继续执行。可以类比成水流,jvm运行时就像是水一直在流,断点相当于在水流经的某一处放置档板,使其完全停在此处,一旦档板放开,水流继续正常流淌。
具体的实现是基于Java对外提供的专门用于调度和监控虚拟机使用的API,也就是Java Platform Debugger Architecture(JPDA).
关于JPDA需要知道的重点如下:
-
JPDA包括三个层次,图示如下。
image.png -
通过JDI与被调试的虚拟机进程通信,底层是通过TCP socket方式实现的。
更多详细说明,参考如下文档:
https://yq.aliyun.com/articles/56?spm=5176.100238.yqhn2.7.NLnzoh
- jconsole连接原理:
底层通过jmx协议来连接、监控和管理虚拟机进程。
jmx协议实现时可以支持多种底层网络协议如rmi,http等
至此,还是没有想清楚 为什么idea中debug模式启动的进程不能被jconsole连接。
进一步查看运行模式和debug模式启动进程的差别:
运行模式:
-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=56196:/Applications/IntelliJ IDEA.app/Contents/bin
debug模式:
-javaagent:/Users/mac/Library/Caches/IntelliJIdea2018.2/captureAgent/debugger-agent.jar=file:/private/var/folders/58/kbmn4r191jggdg23jnph_q4c0000gn/T/capture.props
- -javaagent实际上是jvm提供的一个类似AOP的方式,允许程序运行之前,修改运行的字节码。就是在运行main函数之前,jvm会先调用javaagent里指定的一个类似interceptor的程序。相当于开了一个proxy或者是agent。
关于javaagent的使用详见:
https://www.cnblogs.com/aspirant/p/8796974.html
这两种模式主要差别在于这个javaagent是不同的。
未完待续:
除了这个不同以外,未发现其他不同。
而这个不同与jmx连接也没啥关系。
暂时没有其他调查思路。
网友评论