diff --git a/vjtop/pom.xml b/vjtop/pom.xml
index bf3a7dfb..8fa550e2 100644
--- a/vjtop/pom.xml
+++ b/vjtop/pom.xml
@@ -25,13 +25,13 @@
jopt-simple
4.9
-
+
junit
junit
@@ -145,6 +145,31 @@
+
+
+
+ jdk9
+
+ [1.9,)
+
+
+
+
+ default-jdk
+
+ (,1.8]
+
+
+
+ com.sun
+ tools
+ ${java.version}
+ system
+ ${toolsjar}
+
+
+
+
diff --git a/vjtop/src/main/assembly/vjtop.sh b/vjtop/src/main/assembly/vjtop.sh
index 2a5602f0..6741b955 100644
--- a/vjtop/src/main/assembly/vjtop.sh
+++ b/vjtop/src/main/assembly/vjtop.sh
@@ -9,16 +9,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="-Xms256m -Xmx256m -XX:NewRatio=1 -Xss256k -XX:+UseSerialGC -XX:CICompilerCount=2 -Xverify:none -XX:AutoBoxCacheMax=20000"
+DIR=$( cd $(dirname $0) ; pwd -P )
"$JAVA_HOME"/bin/java $JAVA_OPTS -cp "$DIR/vjtop.jar:$TOOLSJAR" com.vip.vjtools.vjtop.VJTop "$@"
exit $?
diff --git a/vjtop/src/main/java/com/vip/vjtools/vjtop/VMDetailView.java b/vjtop/src/main/java/com/vip/vjtools/vjtop/VMDetailView.java
index 2a53ee4a..a65d5114 100755
--- a/vjtop/src/main/java/com/vip/vjtools/vjtop/VMDetailView.java
+++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/VMDetailView.java
@@ -157,12 +157,16 @@ private void printJvmInfoAsConsole() {
Formats.toColor(vmInfo.classLoaded.current, warning.loadClass), vmInfo.classUnLoaded,
Formats.toColor(vmInfo.classLoaded.delta, warning.newClass));
- System.out.printf(" HEAP: %s eden, %s sur, %s old%n", Formats.formatUsage(vmInfo.eden),
- Formats.formatUsage(vmInfo.sur), Formats.formatUsageWithColor(vmInfo.old, warning.old));
+ if (vmInfo.ygcStrategy.equals("ZGC")) {
+ System.out.printf(" HEAP: %s%n", Formats.formatUsage(vmInfo.eden));
+ } else {
+ System.out.printf(" HEAP: %s eden, %s sur, %s old%n", Formats.formatUsage(vmInfo.eden),
+ Formats.formatUsage(vmInfo.sur), Formats.formatUsageWithColor(vmInfo.old, warning.old));
+ }
System.out.printf(" NON-HEAP: %s %s, %s codeCache", Formats.formatUsageWithColor(vmInfo.perm, warning.perm),
vmInfo.permGenName, Formats.formatUsageWithColor(vmInfo.codeCache, warning.codeCache));
- if (vmInfo.jvmMajorVersion >= 8) {
+ if (vmInfo.jvmMajorVersion >= 8 && !vmInfo.ygcStrategy.equals("ZGC")) {
System.out.printf(", %s ccs", Formats.formatUsage(vmInfo.ccs));
}
System.out.println("");
@@ -172,13 +176,21 @@ private void printJvmInfoAsConsole() {
Formats.toMB(vmInfo.direct.max), Formats.toMB(vmInfo.map.used), Formats.toMB(vmInfo.map.committed),
vmInfo.map.max, Formats.toMB(vmInfo.threadStackSize * vmInfo.threadActive));
+ // gc strategy
+ System.out.printf(" GC-STRATEGY: %s / %s%n", vmInfo.ygcStrategy, vmInfo.fullgcStrategy);
+ // gc count
long ygcCount = vmInfo.ygcCount.delta;
long ygcTime = vmInfo.ygcTimeMills.delta;
long avgYgcTime = ygcCount == 0 ? 0 : ygcTime / ygcCount;
long fgcCount = vmInfo.fullgcCount.delta;
- System.out.printf(" GC: %s/%sms/%sms ygc, %s/%dms fgc", Formats.toColor(ygcCount, warning.ygcCount),
- Formats.toColor(ygcTime, warning.ygcTime), Formats.toColor(avgYgcTime, warning.ygcAvgTime),
- Formats.toColor(fgcCount, warning.fullgcCount), vmInfo.fullgcTimeMills.delta);
+ if (vmInfo.ygcStrategy.equals("ZGC")) {
+ System.out.printf(" GC: %s/%sms/%sms zgc", Formats.toColor(ygcCount, warning.ygcCount),
+ Formats.toColor(ygcTime, warning.ygcTime), Formats.toColor(avgYgcTime, warning.ygcAvgTime));
+ } else {
+ System.out.printf(" GC: %s/%sms/%sms ygc, %s/%dms fgc", Formats.toColor(ygcCount, warning.ygcCount),
+ Formats.toColor(ygcTime, warning.ygcTime), Formats.toColor(avgYgcTime, warning.ygcAvgTime),
+ Formats.toColor(fgcCount, warning.fullgcCount), vmInfo.fullgcTimeMills.delta);
+ }
if (vmInfo.perfDataSupport) {
System.out.printf(" | SAFE-POINT: %s count, %sms time, %dms syncTime",
@@ -536,6 +548,7 @@ public static ThreadInfoMode parseInt(String mode) {
public enum OutputFormat {
console(true), cleanConsole(false), text(false);
+
OutputFormat(boolean ansi) {
this.ansi = ansi;
}
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 2fab39dd..0c36ba71 100755
--- a/vjtop/src/main/java/com/vip/vjtools/vjtop/VMInfo.java
+++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/VMInfo.java
@@ -7,9 +7,11 @@
import java.util.Locale;
import java.util.Map;
+import com.sun.management.GarbageCollectorMXBean;
import com.vip.vjtools.vjtop.data.PerfData;
import com.vip.vjtools.vjtop.data.ProcFileData;
import com.vip.vjtools.vjtop.data.jmx.JmxClient;
+import com.vip.vjtools.vjtop.data.jmx.JmxGarbageCollectorManager;
import com.vip.vjtools.vjtop.data.jmx.JmxMemoryPoolManager;
import com.vip.vjtools.vjtop.util.Formats;
import com.vip.vjtools.vjtop.util.Utils;
@@ -65,8 +67,10 @@ public class VMInfo {
public double cpuLoad = 0.0;
public double singleCoreCpuLoad = 0.0;
+ public String ygcStrategy = "";
public Rate ygcCount = new Rate();
public Rate ygcTimeMills = new Rate();
+ public String fullgcStrategy = "";
public Rate fullgcCount = new Rate();
public Rate fullgcTimeMills = new Rate();
public String currentGcCause = "";
@@ -179,9 +183,8 @@ private void init() throws IOException {
Map taregetVMSystemProperties = jmxClient.getRuntimeMXBean().getSystemProperties();
osUser = taregetVMSystemProperties.get("user.name");
jvmVersion = taregetVMSystemProperties.get("java.version");
- jvmMajorVersion = getJavaMajorVersion(jvmVersion);
+ jvmMajorVersion = Utils.getJavaMajorVersion(taregetVMSystemProperties.get("java.specification.version"));
permGenName = jvmMajorVersion >= 8 ? "metaspace" : "perm";
-
threadStackSize = 1024
* Long.parseLong(jmxClient.getHotSpotDiagnosticMXBean().getVMOption("ThreadStackSize").getValue());
maxDirectMemorySize = Long
@@ -337,9 +340,21 @@ private void updateMemoryPool() {
try {
JmxMemoryPoolManager memoryPoolManager = jmxClient.getMemoryPoolManager();
- eden = new Usage(memoryPoolManager.getEdenMemoryPool().getUsage());
- old = new Usage(memoryPoolManager.getOldMemoryPool().getUsage());
- warningRule.updateOld(old.max);
+
+ MemoryPoolMXBean edenMXBean = memoryPoolManager.getEdenMemoryPool();
+ if (edenMXBean != null) {
+ eden = new Usage(edenMXBean.getUsage());
+ } else {
+ eden = new Usage();
+ }
+
+ MemoryPoolMXBean oldMXBean = memoryPoolManager.getOldMemoryPool();
+ if (oldMXBean != null) {
+ old = new Usage(oldMXBean.getUsage());
+ warningRule.updateOld(old.max);
+ } else {
+ old = new Usage();
+ }
MemoryPoolMXBean survivorMemoryPool = memoryPoolManager.getSurvivorMemoryPool();
if (survivorMemoryPool != null) {
@@ -348,8 +363,13 @@ private void updateMemoryPool() {
sur = new Usage();
}
- perm = new Usage(memoryPoolManager.getPermMemoryPool().getUsage());
- warningRule.updatePerm(perm.max);
+ MemoryPoolMXBean permMXBean = memoryPoolManager.getPermMemoryPool();
+ if (permMXBean != null) {
+ perm = new Usage(permMXBean.getUsage());
+ warningRule.updatePerm(perm.max);
+ } else {
+ perm = new Usage();
+ }
if (jvmMajorVersion >= 8) {
MemoryPoolMXBean compressedClassSpaceMemoryPool = memoryPoolManager.getCompressedClassSpaceMemoryPool();
@@ -360,7 +380,12 @@ private void updateMemoryPool() {
}
}
- codeCache = new Usage(memoryPoolManager.getCodeCacheMemoryPool().getUsage());
+ MemoryPoolMXBean memoryPoolMXBean = memoryPoolManager.getCodeCacheMemoryPool();
+ if (memoryPoolMXBean != null) {
+ codeCache = new Usage(memoryPoolMXBean.getUsage());
+ } else {
+ codeCache = new Usage();
+ }
direct = new Usage(jmxClient.getBufferPoolManager().getDirectBufferPoolUsed(),
jmxClient.getBufferPoolManager().getDirectBufferPoolCapacity(), maxDirectMemorySize);
@@ -385,13 +410,18 @@ private void updateGC() {
}
} else if (isJmxStateOk()) {
try {
- ygcCount.update(jmxClient.getGarbageCollectorManager().getYoungCollector().getCollectionCount());
- ygcTimeMills.update(jmxClient.getGarbageCollectorManager().getYoungCollector().getCollectionTime());
-
- if (jmxClient.getGarbageCollectorManager().getFullCollector() != null) {
- fullgcCount.update(jmxClient.getGarbageCollectorManager().getFullCollector().getCollectionCount());
- fullgcTimeMills
- .update(jmxClient.getGarbageCollectorManager().getFullCollector().getCollectionTime());
+ JmxGarbageCollectorManager gcManager = jmxClient.getGarbageCollectorManager();
+
+ GarbageCollectorMXBean ygcMXBean = gcManager.getYoungCollector();
+ ygcStrategy = gcManager.getYgcStrategy();
+ ygcCount.update(ygcMXBean.getCollectionCount());
+ ygcTimeMills.update(ygcMXBean.getCollectionTime());
+
+ GarbageCollectorMXBean fullgcMXBean = gcManager.getFullCollector();
+ if (fullgcMXBean != null) {
+ fullgcStrategy = gcManager.getFgcStrategy();
+ fullgcCount.update(fullgcMXBean.getCollectionCount());
+ fullgcTimeMills.update(fullgcMXBean.getCollectionTime());
}
} catch (Exception e) {
handleJmxFetchDataError(e);
@@ -480,17 +510,6 @@ public boolean isJmxStateOk() {
return state != VMInfoState.ATTACHED_UPDATE_ERROR && state != VMInfoState.DETACHED;
}
- private static int getJavaMajorVersion(String jvmVersion) {
- if (jvmVersion.startsWith("1.8")) {
- return 8;
- } else if (jvmVersion.startsWith("1.7")) {
- return 7;
- } else if (jvmVersion.startsWith("1.6")) {
- return 6;
- } else {
- return 0;
- }
- }
public enum VMInfoState {
INIT, ERROR_DURING_ATTACH, ATTACHED, ATTACHED_UPDATE_ERROR, DETACHED
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 138c52a1..eaa7793b 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
@@ -55,6 +55,7 @@
import com.sun.management.OperatingSystemMXBean;
import com.sun.management.ThreadMXBean;
import com.sun.tools.attach.VirtualMachine;
+import com.vip.vjtools.vjtop.util.Utils;
@SuppressWarnings("restriction")
public class JmxClient {
@@ -94,7 +95,7 @@ public void connect(String pid, String jmxHostAndPort) throws Exception {
JMXServiceURL jmxUrl = new JMXServiceURL(
"service:jmx:rmi://" + jmxHostAndPort + "/jndi/rmi://" + jmxHostAndPort + "/jmxrmi");
Map credentials = new HashMap(1);
- String[] creds = new String[] { null, null };
+ String[] creds = new String[]{null, null};
credentials.put(JMXConnector.CREDENTIALS, creds);
this.jmxc = JMXConnectorFactory.connect(jmxUrl, credentials);
@@ -235,31 +236,40 @@ public String attachToGetConnectorAddress() throws Exception {
// 3. 未启动,尝试启动
String home = vm.getSystemProperties().getProperty("java.home");
+ int version = Utils.getJavaMajorVersion(vm.getSystemProperties().getProperty("java.specification.version"));
+
+ if (version <= 8) {
+ // 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);
+ if (!f.exists()) {
+ throw new IOException("Management agent not found");
+ }
+ }
+ agentPath = f.getCanonicalPath();
+ vm.loadAgent(agentPath, "com.sun.management.jmxremote");
- // 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);
- if (!f.exists()) {
- throw new IOException("Management agent not found");
+ // 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");
}
+ } else {
+ // for jdk9 or later
+ vm.startLocalManagementAgent();
}
- agentPath = f.getCanonicalPath();
- vm.loadAgent(agentPath, "com.sun.management.jmxremote");
-
- // 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");
- }
return address;
} finally {
@@ -301,7 +311,7 @@ private Snapshot() {
public static SnapshotMBeanServerConnection newSnapshot(MBeanServerConnection mbsc) {
final InvocationHandler ih = new SnapshotInvocationHandler(mbsc);
return (SnapshotMBeanServerConnection) Proxy.newProxyInstance(Snapshot.class.getClassLoader(),
- new Class[] { SnapshotMBeanServerConnection.class }, ih);
+ new Class[]{SnapshotMBeanServerConnection.class}, ih);
}
}
diff --git a/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxGarbageCollectorManager.java b/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxGarbageCollectorManager.java
index 82481b11..813675fb 100644
--- a/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxGarbageCollectorManager.java
+++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxGarbageCollectorManager.java
@@ -12,6 +12,8 @@ public class JmxGarbageCollectorManager {
private GarbageCollectorMXBean ygcMXBean = null;
private GarbageCollectorMXBean fgcMXBean = null;
+ private String ygcStrategy = null;
+ private String fgcStrategy = null;
public static String getByGcName(String gcName, String defaultName) {
@@ -25,16 +27,21 @@ public JmxGarbageCollectorManager(MBeanServerConnection connection) throws IOExc
List gcMXBeans = ManagementFactory.getPlatformMXBeans(connection,
GarbageCollectorMXBean.class);
+
for (GarbageCollectorMXBean gcMXBean : gcMXBeans) {
String gcName = gcMXBean.getName();
if ("Copy".equals(gcName) || "PS Scavenge".equals(gcName) || "ParNew".equals(gcName)
- || "G1 Young Generation".equals(gcName)) {
+ || "G1 Young Generation".equals(gcName) || "ZGC".equals(gcName)) {
ygcMXBean = gcMXBean;
+ ygcStrategy = gcName;
} else if ("MarkSweepCompact".equals(gcName) || "PS MarkSweep".equals(gcName)
|| "ConcurrentMarkSweep".equals(gcName) || "G1 Old Generation".equals(gcName)) {
fgcMXBean = gcMXBean;
+ fgcStrategy = gcName;
} else {
+ // default
ygcMXBean = gcMXBean;
+ ygcStrategy = gcName;
}
}
}
@@ -46,4 +53,13 @@ public synchronized GarbageCollectorMXBean getYoungCollector() {
public synchronized GarbageCollectorMXBean getFullCollector() {
return fgcMXBean;
}
+
+ public String getYgcStrategy() {
+ return ygcStrategy;
+ }
+
+ public String getFgcStrategy() {
+ return fgcStrategy;
+ }
+
}
diff --git a/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxMemoryPoolManager.java b/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxMemoryPoolManager.java
index 09567b14..a137fb9d 100644
--- a/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxMemoryPoolManager.java
+++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxMemoryPoolManager.java
@@ -15,7 +15,10 @@ public class JmxMemoryPoolManager {
public static final String PERM = "perm";
public static final String METASPACE = "metaspace";// JDK8永久代名称
public static final String CODE_CACHE = "code cache";
- public static final String COMPRESSED_CLASS_SPACE = "compressed class space";
+ public static final String CODEHEAP = "codeheap";
+ public static final String CODECACHE = "codecache";
+ public static final String ZHEAP = "zheap"; // for zgc
+ public static final String COMPRESSED_CLASS_SPACE = "compressed class space"; // zgc not support until jdk15
private MemoryPoolMXBean survivorMemoryPool = null;
private MemoryPoolMXBean edenMemoryPool = null;
@@ -32,13 +35,14 @@ public JmxMemoryPoolManager(MBeanServerConnection connection) throws IOException
String lowerCaseName = name.toLowerCase();
if (lowerCaseName.contains(SURVIVOR)) {
survivorMemoryPool = memoryPool;
- } else if (lowerCaseName.contains(EDEN)) {
+ } else if (lowerCaseName.contains(EDEN) || lowerCaseName.contains(ZHEAP)) {
edenMemoryPool = memoryPool;
} else if (lowerCaseName.contains(OLD) || lowerCaseName.contains(TENURED)) {
oldMemoryPool = memoryPool;
} else if (lowerCaseName.contains(PERM) || lowerCaseName.contains(METASPACE)) {
permMemoryPool = memoryPool;
- } else if (lowerCaseName.contains(CODE_CACHE)) {
+ } else if (lowerCaseName.contains(CODE_CACHE) || lowerCaseName.contains(CODEHEAP)
+ || lowerCaseName.contains(CODECACHE)) {
codeCacheMemoryPool = memoryPool;
} else if (lowerCaseName.contains(COMPRESSED_CLASS_SPACE)) {
compressedClassSpaceMemoryPool = memoryPool;
diff --git a/vjtop/src/main/java/com/vip/vjtools/vjtop/util/Utils.java b/vjtop/src/main/java/com/vip/vjtools/vjtop/util/Utils.java
index ebd10709..3a89df2f 100644
--- a/vjtop/src/main/java/com/vip/vjtools/vjtop/util/Utils.java
+++ b/vjtop/src/main/java/com/vip/vjtools/vjtop/util/Utils.java
@@ -70,4 +70,20 @@ public static void sleep(long mills) {
} catch (InterruptedException e) {
}
}
+
+ public 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;
+ }
+ }
+ }
}