diff --git a/vjmxcli/pom.xml b/vjmxcli/pom.xml index efeca08a..d3475c6e 100644 --- a/vjmxcli/pom.xml +++ b/vjmxcli/pom.xml @@ -19,13 +19,13 @@ - + @@ -129,6 +129,31 @@ + + + + jdk9 + + [1.9,) + + + + + default-jdk + + (,1.8] + + + + com.sun + tools + ${java.version} + system + ${toolsjar} + + + + diff --git a/vjmxcli/src/main/assembly/vjmxcli.sh b/vjmxcli/src/main/assembly/vjmxcli.sh index 391f9af8..85463d88 100644 --- a/vjmxcli/src/main/assembly/vjmxcli.sh +++ b/vjmxcli/src/main/assembly/vjmxcli.sh @@ -11,15 +11,61 @@ if [ ! -d "$JAVA_HOME" ] ; then exit 1 fi -TOOLSJAR="$JAVA_HOME/lib/tools.jar" -if [ ! -f "$TOOLSJAR" ] ; then - echo "$TOOLSJAR doesn't exist" >&2 - exit 1 + +# returns the JDK version. +# 8 for 1.8.0_nn, 9 for 9-ea etc, and "no_java" for undetected +GET_JDK_VERSION() { + local result + local java_cmd + if [[ -n $(type -p java) ]] + then + java_cmd=java + elif [[ (-n "$JAVA_HOME") && (-x "$JAVA_HOME/bin/java") ]] + then + java_cmd="$JAVA_HOME/bin/java" + fi + local IFS=$'\n' + # remove \r for Cygwin + local lines=$("$java_cmd" -Xms32M -Xmx32M -version 2>&1 | tr '\r' '\n') + if [[ -z $java_cmd ]] + then + result=no_java + else + for line in $lines; do + if [[ (-z $result) && ($line = *"version \""*) ]] + then + local ver=$(echo $line | sed -e 's/.*version "\(.*\)"\(.*\)/\1/; 1q') + # on macOS, sed doesn't support '?' + if [[ $ver = "1."* ]] + then + result=$(echo $ver | sed -e 's/1\.\([0-9]*\)\(.*\)/\1/; 1q') + else + result=$(echo $ver | sed -e 's/\([0-9]*\)\(.*\)/\1/; 1q') + fi + fi + done + fi + echo "$result" +} + +JDK_VERSION=$(GET_JDK_VERSION) +echo "JDK_VERSION : $JDK_VERSION" + +# jdk 8 and before +if [[ $JDK_VERSION -le 8 ]]; then + TOOLSJAR="$JAVA_HOME/lib/tools.jar" + if [ ! -f "$TOOLSJAR" ] ; then + echo "$TOOLSJAR doesn't exist" >&2 + exit 1 + fi + JAVA_OPTS="-Xms256m -Xmx256m -XX:NewRatio=1 -Xss256k -XX:+UseSerialGC -XX:CICompilerCount=2 -Xverify:none -XX:AutoBoxCacheMax=20000" +else + # jdk 9 or later + JAVA_OPTS="-Xms256m -Xmx256m -XX:NewRatio=1 -Xss256k -XX:+UseSerialGC -XX:CICompilerCount=2 -XX:AutoBoxCacheMax=20000" fi -DIR=$( cd $(dirname $0) ; pwd -P ) -JAVA_OPTS="-Xms96m -Xmx96m -Xmn64m -Xss256k -XX:+UseSerialGC -Djava.compiler=NONE -Xverify:none -XX:AutoBoxCacheMax=20000" +DIR=$( cd $(dirname $0) ; pwd -P ) "$JAVA_HOME"/bin/java $JAVA_OPTS -cp "$DIR/vjmxcli.jar:$TOOLSJAR" com.vip.vjtools.jmx.Client $* \ No newline at end of file diff --git a/vjmxcli/src/main/java/com/vip/vjtools/jmx/Client.java b/vjmxcli/src/main/java/com/vip/vjtools/jmx/Client.java index 63777f1e..06adf212 100644 --- a/vjmxcli/src/main/java/com/vip/vjtools/jmx/Client.java +++ b/vjmxcli/src/main/java/com/vip/vjtools/jmx/Client.java @@ -142,7 +142,7 @@ protected String[] parseUserpass(final String userpass) { if (index <= 0) { throw new RuntimeException("Unable to parse: " + userpass); } - return new String[] { userpass.substring(0, index), userpass.substring(index + 1) }; + return new String[]{userpass.substring(0, index), userpass.substring(index + 1)}; } /** @@ -152,7 +152,7 @@ protected String[] parseUserpass(final String userpass) { */ protected static Map formatCredentials(final String login, final String password) { Map env = null; - String[] creds = new String[] { login, password }; + String[] creds = new String[]{login, password}; env = new HashMap(1); env.put(JMXConnector.CREDENTIALS, creds); return env; @@ -202,39 +202,49 @@ public static String getLocalConnectorAddress(String pid) throws IOException {// } // 3. 未启动,尝试启动 - // JDK8后有更直接的vm.startLocalManagementAgent()方法 - String home = vm.getSystemProperties().getProperty("java.home"); - - // Normally in ${java.home}/jre/lib/management-agent.jar but might - // be in ${java.home}/lib in build environments. - - String agentPath = home + File.separator + "jre" + File.separator + "lib" + File.separator - + "management-agent.jar"; - File f = new File(agentPath); - if (!f.exists()) { - agentPath = home + File.separator + "lib" + File.separator + "management-agent.jar"; - f = new File(agentPath); + int version = getJavaMajorVersion(vm.getSystemProperties().getProperty("java.specification.version")); + if (version >= 8) { + vm.startLocalManagementAgent(); + agentProps = vm.getAgentProperties(); + address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); + } else { + // JDK8后有更直接的vm.startLocalManagementAgent()方法 + String home = vm.getSystemProperties().getProperty("java.home"); + // Normally in ${java.home}/jre/lib/management-agent.jar but might + // be in ${java.home}/lib in build environments. + String agentPath = home + File.separator + "jre" + File.separator + "lib" + File.separator + + "management-agent.jar"; + + File f = new File(agentPath); if (!f.exists()) { - throw new IOException("Management agent not found"); + agentPath = home + File.separator + "lib" + File.separator + "management-agent.jar"; + f = new File(agentPath); + if (!f.exists()) { + throw new IOException("Management agent not found"); + } } - } - agentPath = f.getCanonicalPath(); - try { - vm.loadAgent(agentPath, "com.sun.management.jmxremote"); - } catch (AgentLoadException x) { - IOException ioe = new IOException(x.getMessage()); - ioe.initCause(x); - throw ioe; - } catch (AgentInitializationException x) { - IOException ioe = new IOException(x.getMessage()); - ioe.initCause(x); - throw ioe; - } + agentPath = f.getCanonicalPath(); + try { + vm.loadAgent(agentPath, "com.sun.management.jmxremote"); + } catch (AgentLoadException x) { + // 高版本 attach 低版本jdk 抛异常:com.sun.tools.attach.AgentLoadException: 0,实际上是成功的; + // 根因: HotSpotVirtualMachine.loadAgentLibrary 高版本jdk实现不一样了 + if (!"0".equals(x.getMessage())) { + IOException ioe = new IOException(x.getMessage()); + ioe.initCause(x); + throw ioe; + } + } catch (AgentInitializationException x) { + IOException ioe = new IOException(x.getMessage()); + ioe.initCause(x); + throw ioe; + } - // 4. 再次获取connector address - agentProps = vm.getAgentProperties(); - address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); + // 4. 再次获取connector address + agentProps = vm.getAgentProperties(); + address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); + } if (address == null) { throw new IOException("Fails to find connector address"); @@ -311,7 +321,7 @@ protected Object[] execute(final String hostport, final String login, final Stri public Object[] executeOneCmd(final String hostport, final String login, final String password, final String beanname, final String command) throws Exception { - return execute(hostport, login, password, beanname, new String[] { command }, true); + return execute(hostport, login, password, beanname, new String[]{command}, true); } /** @@ -386,7 +396,7 @@ protected static Object[] doBeans(final MBeanServerConnection mbsc, final Object } buffer.append("\n"); } - result = new String[] { buffer.toString() }; + result = new String[]{buffer.toString()}; } return result; } @@ -404,7 +414,7 @@ protected static Object[] doBean(MBeanServerConnection mbsc, ObjectInstance inst throws Exception { // If no command, then print out list of attributes and operations. if (command == null || command.length <= 0) { - return new String[] { listOptions(mbsc, instance) }; + return new String[]{listOptions(mbsc, instance)}; } // Maybe multiple attributes/operations listed on one command line. @@ -614,8 +624,8 @@ protected static Object doAttributeOperation(MBeanServerConnection mbsc, ObjectI // Get first attribute of name 'cmd'. Assumption is no method // overrides. Then, look at the attribute and use its type. MBeanAttributeInfo info = (MBeanAttributeInfo) getFeatureInfo(infos, parse.getCmd()); - java.lang.reflect.Constructor c = Class.forName(info.getType()).getConstructor(new Class[] { String.class }); - Attribute a = new Attribute(parse.getCmd(), c.newInstance(new Object[] { parse.getArgs()[0] })); + java.lang.reflect.Constructor c = Class.forName(info.getType()).getConstructor(new Class[]{String.class}); + Attribute a = new Attribute(parse.getCmd(), c.newInstance(new Object[]{parse.getArgs()[0]})); mbsc.setAttribute(instance.getObjectName(), a); return null; } @@ -644,8 +654,8 @@ protected static Object doBeanOperation(MBeanServerConnection mbsc, ObjectInstan for (int i = 0; i < paraminfosLength; i++) { MBeanParameterInfo paraminfo = paraminfos[i]; java.lang.reflect.Constructor c = Class.forName(paraminfo.getType()) - .getConstructor(new Class[] { String.class }); - params[i] = c.newInstance(new Object[] { parse.getArgs()[i] }); + .getConstructor(new Class[]{String.class}); + params[i] = c.newInstance(new Object[]{parse.getArgs()[i]}); signature[i] = paraminfo.getType(); } result = mbsc.invoke(instance.getObjectName(), parse.getCmd(), params, signature); @@ -760,4 +770,20 @@ public synchronized String format(LogRecord record) { } } + private static int getJavaMajorVersion(String javaSpecificationVersion) { + if (javaSpecificationVersion.startsWith("1.8")) { + return 8; + } else if (javaSpecificationVersion.startsWith("1.7")) { + return 7; + } else if (javaSpecificationVersion.startsWith("1.6")) { + return 6; + } else { + try { + return Integer.parseInt(javaSpecificationVersion); + } catch (NumberFormatException e) { + return 0; + } + } + } + } diff --git a/vjmxcli/src/main/java/com/vip/vjtools/jmx/ExtraCommand.java b/vjmxcli/src/main/java/com/vip/vjtools/jmx/ExtraCommand.java index 71e00469..b3c8af2d 100644 --- a/vjmxcli/src/main/java/com/vip/vjtools/jmx/ExtraCommand.java +++ b/vjmxcli/src/main/java/com/vip/vjtools/jmx/ExtraCommand.java @@ -24,9 +24,9 @@ private void gcUtilCommand(MBeanServerConnection mbsc, int interval) throws Exce String[] commands; if (getJavaVersion(mbsc) > 7) { - commands = new String[] { "S", "S", "E", "O", "M", "CCS", "YGC", "YGCT", "FGC", "FGCT", "GCT" }; + commands = new String[]{"S", "S", "E", "O", "M", "CCS", "YGC", "YGCT", "FGC", "FGCT", "GCT"}; } else { - commands = new String[] { "S", "S", "E", "O", "P", "YGC", "YGCT", "FGC", "FGCT", "GCT" }; + commands = new String[]{"S", "S", "E", "O", "P", "YGC", "YGCT", "FGC", "FGCT", "GCT"}; } for (String commmand : commands) { @@ -84,14 +84,18 @@ private Object[] executGCutil(final String[] commands, GCutilExpression gcE) thr public static int getJavaVersion(final MBeanServerConnection mbsc) throws Exception { Object version = mbsc.getAttribute(Client.getObjectName("java.lang:type=Runtime"), "SpecVersion"); String javaVersion = version.toString(); - if (javaVersion.startsWith("1.8") || Double.parseDouble(javaVersion.substring(0, 3)) > 1.7) { + if (javaVersion.startsWith("1.8")) { return 8; } else if (javaVersion.startsWith("1.7")) { return 7; } else if (javaVersion.startsWith("1.6")) { return 6; } else { - return 0; + try { + return Integer.parseInt(javaVersion); + } catch (NumberFormatException e) { + return 0; + } } } } diff --git a/vjmxcli/src/main/java/com/vip/vjtools/jmx/GCutilExpression.java b/vjmxcli/src/main/java/com/vip/vjtools/jmx/GCutilExpression.java index 3ddcd5f4..9aa64b23 100644 --- a/vjmxcli/src/main/java/com/vip/vjtools/jmx/GCutilExpression.java +++ b/vjmxcli/src/main/java/com/vip/vjtools/jmx/GCutilExpression.java @@ -103,10 +103,16 @@ public Double getYGCT() throws Exception { } public Object getFGC() throws Exception { + if (fgcCollector == null) { + return 0; + } return getAttribute(fgcCollector, COLLECTION_COUNT_ATTRIBUTE); } public Double getFGCT() throws Exception { + if (fgcCollector == null) { + return 0.0; + } return Double.parseDouble(getAttribute(fgcCollector, COLLECTION_TIME_ATTRIBUTE).toString()) / 1000; }