diff --git a/vjtop/README.md b/vjtop/README.md index b98e7721..4e7c7b88 100644 --- a/vjtop/README.md +++ b/vjtop/README.md @@ -222,14 +222,27 @@ ERROR: Could not attach to process. ``` -1. 执行vjtop的用户,对/tmp/.java_pid$PID 文件有读写权限,该文件权限为srw------- 1,所以需要相同用户或root权限用户 sudo执行。 +1. 执行vjtop的用户,对/tmp/.java_pid$PID 文件有读写权限,该文件权限为srw------- 1,所以需要相同用户 -2. /tmp/.java_pid$PID 文件再首次连接时会生成,但如果生成之后被/tmp 目录的清理程序错误删除,JVM将不再能连入,只能重启应用。 +2. /tmp/.java_pid$PID 文件在首次连接时会生成,但如果生成之后被/tmp 目录的清理程序错误删除,JVM将不再能连入,只能重启应用。 3. 目标JVM使用启动参数-Djava.io.tmpdir,重定向了tmp目录路径 4. 目标JVM使用启动参数-XX:+DisableAttachMechanism禁止了attach +如果实在没有办法attach,可以考虑在原目标进程中配置JMX启动参数,设定JMX的地址与端口,然后在vjtop中指定 + +目标进程的JVM参数: +``` +-Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.port=7001 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.X=false -Dcom.sun.management.jmxremote.ssl=false +``` + +vjtop的命令(since 1.0.3): + +``` +./vjtop.sh -j 127.0.0.1:7001 +``` + # 4. 改进点 diff --git a/vjtop/src/main/java/com/vip/vjtools/vjtop/InteractiveTask.java b/vjtop/src/main/java/com/vip/vjtools/vjtop/InteractiveTask.java index 5ba1b11c..e947bc79 100644 --- a/vjtop/src/main/java/com/vip/vjtools/vjtop/InteractiveTask.java +++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/InteractiveTask.java @@ -157,7 +157,7 @@ private void changeThreadLimit() { if (threadLimit != app.view.threadLimit) { app.view.threadLimit = threadLimit; if (app.nextFlushTime() > 1) { - tty.println(" Number of threads to display changed to " + threadLimit + "for next flush (" + tty.println(" Number of threads to display changed to " + threadLimit + " for next flush (" + app.nextFlushTime() + "s later)"); } } else { diff --git a/vjtop/src/main/java/com/vip/vjtools/vjtop/VJTop.java b/vjtop/src/main/java/com/vip/vjtools/vjtop/VJTop.java index 746289c6..31293b95 100755 --- a/vjtop/src/main/java/com/vip/vjtools/vjtop/VJTop.java +++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/VJTop.java @@ -45,6 +45,9 @@ private static OptionParser createOptionParser() { parser.acceptsAll(Arrays.asList(new String[] { "l", "limit" }), "Number of threads to display ( default to 10 threads)").withRequiredArg().ofType(Integer.class); + parser.acceptsAll(Arrays.asList(new String[] { "j", "jmxurl" }), + "JMX url like 127.0.0.1:7001 when VM attach is not work").withRequiredArg().ofType(String.class); + // detail mode parser.accepts("cpu", "default mode in detail view, display thread cpu usage and sort by thread delta cpu time "); @@ -59,7 +62,6 @@ private static OptionParser createOptionParser() { public static void main(String[] args) { try { - // 1. create option parser OptionParser parser = createOptionParser(); OptionSet optionSet = parser.parse(args); @@ -72,9 +74,14 @@ public static void main(String[] args) { // 2. create vminfo String pid = parsePid(parser, optionSet); - VMInfo vminfo = VMInfo.processNewVM(pid); + String jmxHostAndPort = null; + if (optionSet.hasArgument("jmxurl")) { + jmxHostAndPort = (String) optionSet.valueOf("jmxurl"); + } + + VMInfo vminfo = VMInfo.processNewVM(pid, jmxHostAndPort); if (vminfo.state != VMInfoState.ATTACHED) { - System.out.println("\nERROR: Could not attach to process, please find reason in README\n"); + System.out.println("\nERROR: Could not attach to process, see the solution in README\n"); return; } diff --git a/vjtop/src/main/java/com/vip/vjtools/vjtop/VMInfo.java b/vjtop/src/main/java/com/vip/vjtools/vjtop/VMInfo.java index cf7cc951..0cdbc2a9 100755 --- a/vjtop/src/main/java/com/vip/vjtools/vjtop/VMInfo.java +++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/VMInfo.java @@ -104,10 +104,10 @@ private VMInfo() { /** * 创建JMX连接并构造VMInfo实例 */ - public static VMInfo processNewVM(String pid) { + public static VMInfo processNewVM(String pid, String jmxHostAndPort) { try { - final JmxClient jmxClient = new JmxClient(pid); - jmxClient.connect(); + final JmxClient jmxClient = new JmxClient(); + jmxClient.connect(pid, jmxHostAndPort); // 注册JMXClient注销的钩子 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { diff --git a/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxClient.java b/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxClient.java index c59e67d8..accd9ede 100755 --- a/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxClient.java +++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxClient.java @@ -66,7 +66,6 @@ public class JmxClient { private String pid; - private JMXServiceURL jmxUrl = null; private MBeanServerConnection mbsc = null; private SnapshotMBeanServerConnection server = null; private JMXConnector jmxc = null; @@ -81,8 +80,7 @@ public class JmxClient { private JmxMemoryPoolManager memoryPoolManager = null; private JmxBufferPoolManager bufferPoolManager = null; - public JmxClient(String pid) throws IOException { - this.pid = pid; + public JmxClient() throws IOException { } public void flush() { @@ -91,13 +89,24 @@ public void flush() { } } - public void connect() throws Exception { + public void connect(String pid, String jmxHostAndPort) throws Exception { + this.pid = pid; + + if (jmxHostAndPort != null) { + JMXServiceURL jmxUrl = new JMXServiceURL( + "service:jmx:rmi://" + jmxHostAndPort + "/jndi/rmi://" + jmxHostAndPort + "/jmxrmi"); + Map credentials = new HashMap(1); + String[] creds = new String[] { null, null }; + credentials.put(JMXConnector.CREDENTIALS, creds); - // 如果jmx agent未启动,主动attach进JVM后加载 - String address = attachToGetConnectorAddress(); + this.jmxc = JMXConnectorFactory.connect(jmxUrl, credentials); + } else { + // 如果jmx agent未启动,主动attach进JVM后加载 + String address = attachToGetConnectorAddress(); - this.jmxUrl = new JMXServiceURL(address); - this.jmxc = JMXConnectorFactory.connect(jmxUrl);// NOSONAR + JMXServiceURL jmxUrl = new JMXServiceURL(address); + this.jmxc = JMXConnectorFactory.connect(jmxUrl);// NOSONAR + } this.mbsc = jmxc.getMBeanServerConnection(); this.server = Snapshot.newSnapshot(mbsc); @@ -230,7 +239,7 @@ private ObjectName createBeanName(String beanName) { @Override public String toString() { - return pid; + return "JMX Client for PID:" + pid; } /**