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
+ * {@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
+ * copy from arthas-vmtool/src/main/java 。 + * 因为动态链接库只能被加载一次,只能使用一份代码。放在spy jar里保证只有一份。 + * TODO 当arthas本身版本升级时,已append 到bootstrap classloader的spy jar不能升级,VmTool的接口可以会调用失败。 + *+ */ +package arthas;