From 932340eac6e4957f58c883a45f593e8164ee19dd Mon Sep 17 00:00:00 2001 From: hengyunabc Date: Thu, 29 Apr 2021 19:28:44 +0800 Subject: [PATCH] add vmtool command, part1. #1781 --- .../src/main/java/arthas/VmTool.java | 24 -- .../src/main/java/arthas/package-info.java | 6 + .../src/test/java/arthas/VmToolTest.java | 4 +- .../com/taobao/arthas/common/VmToolUtils.java | 30 ++ .../core/command/BuiltinCommandPack.java | 2 + .../command/monitor200/VmToolCommand.java | 261 ++++++++++++++++++ .../taobao/arthas/core/util/ClassUtils.java | 2 +- lib/libArthasJniLibrary-x64.dll | Bin 0 -> 86115 bytes lib/libArthasJniLibrary-x64.dylib | Bin 0 -> 52392 bytes lib/libArthasJniLibrary-x64.so | Bin 0 -> 22360 bytes packaging/src/main/assembly/assembly.xml | 3 + pom.xml | 2 +- spy/pom.xml | 10 + spy/src/main/java/arthas/VmTool.java | 109 ++++++++ spy/src/main/java/arthas/VmToolMXBean.java | 48 ++++ spy/src/main/java/arthas/package-info.java | 8 + 16 files changed, 482 insertions(+), 27 deletions(-) create mode 100644 arthas-vmtool/src/main/java/arthas/package-info.java create mode 100644 common/src/main/java/com/taobao/arthas/common/VmToolUtils.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/monitor200/VmToolCommand.java create mode 100644 lib/libArthasJniLibrary-x64.dll create mode 100644 lib/libArthasJniLibrary-x64.dylib create mode 100644 lib/libArthasJniLibrary-x64.so create mode 100644 spy/src/main/java/arthas/VmTool.java create mode 100644 spy/src/main/java/arthas/VmToolMXBean.java create mode 100644 spy/src/main/java/arthas/package-info.java diff --git a/arthas-vmtool/src/main/java/arthas/VmTool.java b/arthas-vmtool/src/main/java/arthas/VmTool.java index ad15d1271..6f7cc0a2a 100644 --- a/arthas-vmtool/src/main/java/arthas/VmTool.java +++ b/arthas-vmtool/src/main/java/arthas/VmTool.java @@ -2,8 +2,6 @@ package arthas; import java.util.ArrayList; -import com.taobao.arthas.common.OSUtils; - /** * @author ZhangZiCheng 2021-02-12 * @author hengyunabc 2021-04-26 @@ -16,24 +14,6 @@ public class VmTool implements VmToolMXBean { */ public final static String JNI_LIBRARY_NAME = "ArthasJniLibrary"; - private static String libName = null; - static { - if (OSUtils.isMac()) { - libName = "libArthasJniLibrary-x64.dylib"; - } - if (OSUtils.isLinux()) { - libName = "libArthasJniLibrary-x64.so"; - if (OSUtils.isArm32()) { - libName = "libArthasJniLibrary-arm.so"; - } else if (OSUtils.isArm64()) { - libName = "libArthasJniLibrary-aarch64.so"; - } - } - if (OSUtils.isWindows()) { - libName = "libArthasJniLibrary-x64.dll"; - } - } - private static VmTool instance; private VmTool() { @@ -58,10 +38,6 @@ public class VmTool implements VmToolMXBean { return instance; } - public static String detectLibName() { - return libName; - } - /** * 检测jni-lib是否正常,如果正常,应该输出OK */ diff --git a/arthas-vmtool/src/main/java/arthas/package-info.java b/arthas-vmtool/src/main/java/arthas/package-info.java new file mode 100644 index 000000000..ba203103d --- /dev/null +++ b/arthas-vmtool/src/main/java/arthas/package-info.java @@ -0,0 +1,6 @@ +/** + *
+ * 修改后要同步到 spy/src/main/java 。
+ * 
+ */ +package arthas; diff --git a/arthas-vmtool/src/test/java/arthas/VmToolTest.java b/arthas-vmtool/src/test/java/arthas/VmToolTest.java index 223a853b5..381a3eaef 100644 --- a/arthas-vmtool/src/test/java/arthas/VmToolTest.java +++ b/arthas-vmtool/src/test/java/arthas/VmToolTest.java @@ -2,6 +2,8 @@ package arthas; import org.junit.Test; +import com.taobao.arthas.common.VmToolUtils; + import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -25,7 +27,7 @@ public class VmToolTest { String path = VmTool.class.getProtectionDomain().getCodeSource().getLocation().getPath(); System.err.println(path); - String libPath = new File(path, VmTool.detectLibName()).getAbsolutePath(); + String libPath = new File(path, VmToolUtils.detectLibName()).getAbsolutePath(); VmTool vmtool = VmTool.getInstance(libPath); //调用native方法,获取已加载的类,不包括小类型(如int) diff --git a/common/src/main/java/com/taobao/arthas/common/VmToolUtils.java b/common/src/main/java/com/taobao/arthas/common/VmToolUtils.java new file mode 100644 index 000000000..7967b415e --- /dev/null +++ b/common/src/main/java/com/taobao/arthas/common/VmToolUtils.java @@ -0,0 +1,30 @@ +package com.taobao.arthas.common; + +/** + * + * @author hengyunabc 2021-04-27 + * + */ +public class VmToolUtils { + private static String libName = null; + static { + if (OSUtils.isMac()) { + libName = "libArthasJniLibrary-x64.dylib"; + } + if (OSUtils.isLinux()) { + libName = "libArthasJniLibrary-x64.so"; + if (OSUtils.isArm32()) { + libName = "libArthasJniLibrary-arm.so"; + } else if (OSUtils.isArm64()) { + libName = "libArthasJniLibrary-aarch64.so"; + } + } + if (OSUtils.isWindows()) { + libName = "libArthasJniLibrary-x64.dll"; + } + } + + public static String detectLibName() { + return libName; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/BuiltinCommandPack.java b/core/src/main/java/com/taobao/arthas/core/command/BuiltinCommandPack.java index 1e9f91953..0bdcd36eb 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/BuiltinCommandPack.java +++ b/core/src/main/java/com/taobao/arthas/core/command/BuiltinCommandPack.java @@ -44,6 +44,7 @@ import com.taobao.arthas.core.command.monitor200.StackCommand; import com.taobao.arthas.core.command.monitor200.ThreadCommand; import com.taobao.arthas.core.command.monitor200.TimeTunnelCommand; import com.taobao.arthas.core.command.monitor200.TraceCommand; +import com.taobao.arthas.core.command.monitor200.VmToolCommand; import com.taobao.arthas.core.command.monitor200.WatchCommand; import com.taobao.arthas.core.shell.command.Command; import com.taobao.arthas.core.shell.command.CommandResolver; @@ -113,6 +114,7 @@ public class BuiltinCommandPack implements CommandResolver { commands.add(Command.create(GrepCommand.class)); commands.add(Command.create(TeeCommand.class)); commands.add(Command.create(ProfilerCommand.class)); + commands.add(Command.create(VmToolCommand.class)); commands.add(Command.create(ShutdownCommand.class)); commands.add(Command.create(StopCommand.class)); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/VmToolCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/VmToolCommand.java new file mode 100644 index 000000000..744bf2c04 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/VmToolCommand.java @@ -0,0 +1,261 @@ +package com.taobao.arthas.core.command.monitor200; + +import java.io.File; +import java.lang.instrument.Instrumentation; +import java.security.CodeSource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.alibaba.arthas.deps.org.slf4j.Logger; +import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; +import com.taobao.arthas.common.VmToolUtils; +import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.express.Express; +import com.taobao.arthas.core.command.express.ExpressException; +import com.taobao.arthas.core.command.express.ExpressFactory; +import com.taobao.arthas.core.command.model.ClassLoaderVO; +import com.taobao.arthas.core.command.model.SearchClassModel; +import com.taobao.arthas.core.shell.cli.Completion; +import com.taobao.arthas.core.shell.cli.CompletionUtils; +import com.taobao.arthas.core.shell.cli.OptionCompleteHandler; +import com.taobao.arthas.core.shell.command.AnnotatedCommand; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassLoaderUtils; +import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.arthas.core.util.SearchUtils; +import com.taobao.arthas.core.view.ObjectView; +import com.taobao.middleware.cli.annotations.DefaultValue; +import com.taobao.middleware.cli.annotations.Description; +import com.taobao.middleware.cli.annotations.Name; +import com.taobao.middleware.cli.annotations.Option; +import com.taobao.middleware.cli.annotations.Summary; + +import arthas.VmTool; + +/** + * + * @author hengyunabc 2021-04-27 + * + */ +//@formatter:off +@Name("vmtool") +@Summary("jvm tool") +@Description(Constants.EXAMPLE + + " vmtool --action getInstances --className demo.MathGame\n" + + " vmtool --action getInstances --className demo.MathGame --express 'instances.size()'\n" + + Constants.WIKI + Constants.WIKI_HOME + "vmtool") +//@formatter:on +public class VmToolCommand extends AnnotatedCommand { + private static final Logger logger = LoggerFactory.getLogger(VmToolCommand.class); + + private VmToolAction action; + private String className; + private String express; + + private String hashCode = null; + private String classLoaderClass; + /** + * default value 2 + */ + private int expand; + + private static String libPath; + private static VmTool vmTool = null; + + static { + String libName = VmToolUtils.detectLibName(); + if (libName != null) { + CodeSource codeSource = VmToolCommand.class.getProtectionDomain().getCodeSource(); + if (codeSource != null) { + try { + File bootJarPath = new File(codeSource.getLocation().toURI().getSchemeSpecificPart()); + File soFile = new File(bootJarPath.getParentFile(), "lib" + File.separator + libName); + if (soFile.exists()) { + libPath = soFile.getAbsolutePath(); + } + } catch (Throwable e) { + logger.error("can not find VmTool so", e); + } + } + } + + } + + @Option(shortName = "a", longName = "action", required = true) + @Description("Action to execute") + public void setAction(VmToolAction action) { + this.action = action; + } + + @Option(longName = "className") + @Description("The class name") + public void setClassName(String className) { + this.className = className; + } + + @Option(shortName = "x", longName = "expand") + @Description("Expand level of object (2 by default)") + @DefaultValue("2") + public void setExpand(int expand) { + this.expand = expand; + } + + @Option(shortName = "c", longName = "classloader") + @Description("The hash code of the special class's classLoader") + public void setHashCode(String hashCode) { + this.hashCode = hashCode; + } + + @Option(longName = "classLoaderClass") + @Description("The class name of the special class's classLoader.") + public void setClassLoaderClass(String classLoaderClass) { + this.classLoaderClass = classLoaderClass; + } + + @Option(longName = "express", required = false) + @Description("The ognl expression, default valueis `instances`.") + public void setExpress(String express) { + this.express = express; + } + + public enum VmToolAction { + getInstances, load + } + + @Override + public void process(final CommandProcess process) { + try { + Instrumentation inst = process.session().getInstrumentation(); + + if (VmToolAction.getInstances.equals(action)) { + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + if (hashCode == null && classLoaderClass != null) { + List matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, + classLoaderClass); + if (matchedClassLoaders.size() == 1) { + classLoader = matchedClassLoaders.get(0); + hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode()); + } else if (matchedClassLoaders.size() > 1) { + Collection classLoaderVOList = ClassUtils + .createClassLoaderVOList(matchedClassLoaders); + SearchClassModel searchclassModel = new SearchClassModel().setClassLoaderClass(classLoaderClass) + .setMatchedClassLoaders(classLoaderVOList); + process.appendResult(searchclassModel); + process.end(-1, + "Found more than one classloader by class name, please specify classloader with '-c '"); + return; + } else { + process.end(-1, "Can not find classloader by class name: " + classLoaderClass + "."); + return; + } + } + + List> matchedClasses = new ArrayList>( + SearchUtils.searchClass(inst, className, false, hashCode)); + int matchedClassSize = matchedClasses.size(); + if (matchedClassSize == 0) { + process.end(-1, "Can not find class by class name: " + className + "."); + return; + } else if (matchedClassSize > 1) { + process.end(-1, "Found more than one class: " + matchedClasses + "."); + return; + } else { + ArrayList instances = vmToolInstance().getInstances(matchedClasses.get(0)); + Object value = instances; + if (express != null) { + Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader); + try { + value = unpooledExpress.bind(new InstancesWrapper(instances)).get(express); + } catch (ExpressException e) { + logger.warn("ognl: failed execute express: " + express, e); + process.end(-1, "Failed to execute ognl, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. "); + } + } + + process.write(new ObjectView(value, this.expand).draw()); + process.end(); + } + } + + process.end(); + } catch (Throwable e) { + logger.error("vmtool error", e); + process.end(1, "vmtool error: " + e.getMessage()); + } + } + + static class InstancesWrapper { + Object instances; + + public InstancesWrapper(Object instances) { + this.instances = instances; + } + + public Object getInstances() { + return instances; + } + + public void setInstances(Object instances) { + this.instances = instances; + } + } + + private VmTool vmToolInstance() { + if (vmTool != null) { + return vmTool; + } else { + vmTool = VmTool.getInstance(libPath); + } + return vmTool; + } + + private Set actions() { + Set values = new HashSet(); + for (VmToolAction action : VmToolAction.values()) { + values.add(action.toString()); + } + return values; + } + + @Override + public void complete(Completion completion) { + List handlers = new ArrayList(); + + handlers.add(new OptionCompleteHandler() { + + @Override + public boolean matchName(String token) { + return "-a".equals(token) || "--action".equals(token); + } + + @Override + public boolean complete(Completion completion) { + return CompletionUtils.complete(completion, actions()); + } + + }); + + handlers.add(new OptionCompleteHandler() { + @Override + public boolean matchName(String token) { + return "--className".equals(token); + } + + @Override + public boolean complete(Completion completion) { + return CompletionUtils.completeClassName(completion); + } + }); + + if (CompletionUtils.completeOptions(completion, handlers)) { + return; + } + + super.complete(completion); + } + +} \ No newline at end of file diff --git a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java index 0d6ca77ae..800f15960 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java @@ -181,7 +181,7 @@ public class ClassUtils { return list.toArray(new String[0]); } - public static List createClassVOList(Set> matchedClasses) { + public static List createClassVOList(Collection> matchedClasses) { List classVOs = new ArrayList(matchedClasses.size()); for (Class aClass : matchedClasses) { ClassVO classVO = createSimpleClassInfo(aClass); diff --git a/lib/libArthasJniLibrary-x64.dll b/lib/libArthasJniLibrary-x64.dll new file mode 100644 index 0000000000000000000000000000000000000000..b9c983aeecd74c8dc313ec75569bb70e50ff47f3 GIT binary patch literal 86115 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 literal 0 HcmV?d00001 diff --git a/lib/libArthasJniLibrary-x64.so b/lib/libArthasJniLibrary-x64.so new file mode 100644 index 0000000000000000000000000000000000000000..b24706f3b19cbf56b365a48c09bd3ddf03e8a1e1 GIT binary patch literal 22360 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 Ja4EP@@!yJ;IS~K= literal 0 HcmV?d00001 diff --git a/packaging/src/main/assembly/assembly.xml b/packaging/src/main/assembly/assembly.xml index f3e8ad630..121523e78 100644 --- a/packaging/src/main/assembly/assembly.xml +++ b/packaging/src/main/assembly/assembly.xml @@ -63,5 +63,8 @@ ../async-profiler + + ../lib + diff --git a/pom.xml b/pom.xml index 81ab30d75..207b72484 100644 --- a/pom.xml +++ b/pom.xml @@ -57,8 +57,8 @@ math-game - spy common + spy arthas-vmtool tunnel-common tunnel-client diff --git a/spy/pom.xml b/spy/pom.xml index 39722bc4d..b0ff9b411 100644 --- a/spy/pom.xml +++ b/spy/pom.xml @@ -10,6 +10,16 @@ arthas-spy arthas-spy + + + com.taobao.arthas + arthas-common + ${project.version} + provided + true + + + arthas-spy diff --git a/spy/src/main/java/arthas/VmTool.java b/spy/src/main/java/arthas/VmTool.java new file mode 100644 index 000000000..6f7cc0a2a --- /dev/null +++ b/spy/src/main/java/arthas/VmTool.java @@ -0,0 +1,109 @@ +package arthas; + +import java.util.ArrayList; + +/** + * @author ZhangZiCheng 2021-02-12 + * @author hengyunabc 2021-04-26 + * @since 3.5.1 + */ +public class VmTool implements VmToolMXBean { + + /** + * 不要修改jni-lib的名称 + */ + public final static String JNI_LIBRARY_NAME = "ArthasJniLibrary"; + + private static VmTool instance; + + private VmTool() { + } + + public static VmTool getInstance() { + return getInstance(null); + } + + public static synchronized VmTool getInstance(String libPath) { + if (instance != null) { + return instance; + } + + if (libPath == null) { + System.loadLibrary(JNI_LIBRARY_NAME); + } else { + System.load(libPath); + } + + instance = new VmTool(); + return instance; + } + + /** + * 检测jni-lib是否正常,如果正常,应该输出OK + */ + private static native String check0(); + + /** + * 获取某个class在jvm中当前所有存活实例 + */ + private static native ArrayList getInstances0(Class klass); + + /** + * 统计某个class在jvm中当前所有存活实例的总占用内存,单位:Byte + */ + private static native long sumInstanceSize0(Class klass); + + /** + * 获取某个实例的占用内存,单位:Byte + */ + private static native long getInstanceSize0(Object instance); + + /** + * 统计某个class在jvm中当前所有存活实例的总个数 + */ + private static native long countInstances0(Class klass); + + /** + * 获取所有已加载的类 + */ + private static native ArrayList> getAllLoadedClasses0(); + + /** + * 包括小类型(如int) + */ + @SuppressWarnings("all") + public static ArrayList getAllClasses() { + return getInstances0(Class.class); + } + + @Override + public String check() { + return check0(); + } + + @Override + public ArrayList getInstances(Class klass) { + return getInstances0(klass); + } + + @Override + public long sumInstanceSize(Class klass) { + return sumInstanceSize0(klass); + } + + @Override + public long getInstanceSize(Object instance) { + return getInstanceSize0(instance); + } + + @Override + public long countInstances(Class klass) { + return countInstances0(klass); + } + + @Override + public ArrayList> getAllLoadedClasses() { + return getAllLoadedClasses0(); + } + +} diff --git a/spy/src/main/java/arthas/VmToolMXBean.java b/spy/src/main/java/arthas/VmToolMXBean.java new file mode 100644 index 000000000..e70a17e7a --- /dev/null +++ b/spy/src/main/java/arthas/VmToolMXBean.java @@ -0,0 +1,48 @@ +package arthas; + +import java.util.ArrayList; + +/** + * VmTool interface for JMX server. How to register VmTool MBean: + * + *
+ * {@code
+ *     ManagementFactory.getPlatformMBeanServer().registerMBean(
+ *             VmTool.getInstance(),
+ *             new ObjectName("arthas:type=VmTool")
+ *     );
+ * }
+ * 
+ * @author hengyunabc 2021-04-26 + */ +public interface VmToolMXBean { + /** + * 检测jni-lib是否正常,如果正常,应该输出OK + */ + public String check(); + + /** + * 获取某个class在jvm中当前所有存活实例 + */ + public ArrayList getInstances(Class klass); + + /** + * 统计某个class在jvm中当前所有存活实例的总占用内存,单位:Byte + */ + public long sumInstanceSize(Class klass); + + /** + * 获取某个实例的占用内存,单位:Byte + */ + public long getInstanceSize(Object instance); + + /** + * 统计某个class在jvm中当前所有存活实例的总个数 + */ + public long countInstances(Class klass); + + /** + * 获取所有已加载的类 + */ + public ArrayList> getAllLoadedClasses(); +} diff --git a/spy/src/main/java/arthas/package-info.java b/spy/src/main/java/arthas/package-info.java new file mode 100644 index 000000000..8762944ed --- /dev/null +++ b/spy/src/main/java/arthas/package-info.java @@ -0,0 +1,8 @@ +/** + *
+ * copy from arthas-vmtool/src/main/java 。
+ * 因为动态链接库只能被加载一次,只能使用一份代码。放在spy jar里保证只有一份。
+ * TODO 当arthas本身版本升级时,已append 到bootstrap classloader的spy jar不能升级,VmTool的接口可以会调用失败。
+ * 
+ */ +package arthas;