Skip to content

Commit

Permalink
#176 bug fix:jdk14报NPE;增加GC策略输出;
Browse files Browse the repository at this point in the history
  • Loading branch information
boxing.yi committed Aug 3, 2020
1 parent 7e06db2 commit a0d6c34
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 63 deletions.
29 changes: 27 additions & 2 deletions vjtop/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
<artifactId>jopt-simple</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<!-- <dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>${java.version}</version>
<scope>system</scope>
<systemPath>${toolsjar}</systemPath>
</dependency>
</dependency> -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down Expand Up @@ -145,6 +145,31 @@
</plugins>
</build>
</profile>


<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
</activation>
<dependencies/>
</profile>
<profile>
<id>default-jdk</id>
<activation>
<jdk>(,1.8]</jdk>
</activation>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>${java.version}</version>
<scope>system</scope>
<systemPath>${toolsjar}</systemPath>
</dependency>
</dependencies>
</profile>

</profiles>

<distributionManagement>
Expand Down
57 changes: 51 additions & 6 deletions vjtop/src/main/assembly/vjtop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 $?
25 changes: 19 additions & 6 deletions vjtop/src/main/java/com/vip/vjtools/vjtop/VMDetailView.java
Original file line number Diff line number Diff line change
Expand Up @@ -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("");
Expand All @@ -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",
Expand Down Expand Up @@ -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;
}
Expand Down
71 changes: 45 additions & 26 deletions vjtop/src/main/java/com/vip/vjtools/vjtop/VMInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 = "";
Expand Down Expand Up @@ -179,9 +183,8 @@ private void init() throws IOException {
Map<String, String> 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
Expand Down Expand Up @@ -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) {
Expand All @@ -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();
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down
48 changes: 29 additions & 19 deletions vjtop/src/main/java/com/vip/vjtools/vjtop/data/jmx/JmxClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}
}

Expand Down
Loading

0 comments on commit a0d6c34

Please sign in to comment.