diff --git a/arthas-vmtool/pom.xml b/arthas-vmtool/pom.xml index bacb2c15f..9766bf3c4 100644 --- a/arthas-vmtool/pom.xml +++ b/arthas-vmtool/pom.xml @@ -121,7 +121,7 @@ -o - -o ${project.build.directory}/classes/${lib_name} + -o ${project.build.directory}/${lib_name} diff --git a/arthas-vmtool/src/main/java/arthas/VmTool.java b/arthas-vmtool/src/main/java/arthas/VmTool.java index 4e2775648..866d47ecb 100644 --- a/arthas-vmtool/src/main/java/arthas/VmTool.java +++ b/arthas-vmtool/src/main/java/arthas/VmTool.java @@ -36,11 +36,6 @@ public class VmTool implements VmToolMXBean { return instance; } - /** - * 检测jni-lib是否正常,如果正常,应该输出OK - */ - private static native String check0(); - private static synchronized native void forceGc0(); /** diff --git a/arthas-vmtool/src/main/java/arthas/package-info.java b/arthas-vmtool/src/main/java/arthas/package-info.java index ba203103d..ddf184f18 100644 --- a/arthas-vmtool/src/main/java/arthas/package-info.java +++ b/arthas-vmtool/src/main/java/arthas/package-info.java @@ -1,6 +1,2 @@ -/** - *
- * 修改后要同步到 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 3cc02f691..8a573f7e1 100644 --- a/arthas-vmtool/src/test/java/arthas/VmToolTest.java +++ b/arthas-vmtool/src/test/java/arthas/VmToolTest.java @@ -10,12 +10,16 @@ import org.junit.Test; import com.taobao.arthas.common.VmToolUtils; -import arthas.VmToolTest.LimitTest; - /** * 以下本地测试的jvm参数均为:-Xms128m -Xmx128m */ public class VmToolTest { + private VmTool initVmTool() { + File path = new File(VmTool.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getParentFile(); + + String libPath = new File(path, VmToolUtils.detectLibName()).getAbsolutePath(); + return VmTool.getInstance(libPath); + } /** * macbook上运行结果如下 @@ -57,14 +61,6 @@ public class VmToolTest { } } - private VmTool initVmTool() { - String path = VmTool.class.getProtectionDomain().getCodeSource().getLocation().getPath(); - System.err.println(path); - - String libPath = new File(path, VmToolUtils.detectLibName()).getAbsolutePath(); - return VmTool.getInstance(libPath); - } - @Test public void testGetInstancesMemoryLeak() { //这里睡20s是为了方便用jprofiler连接上进程 diff --git a/core/pom.xml b/core/pom.xml index 507c6c312..f3119e240 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -120,6 +120,11 @@ arthas-common ${project.version} + + com.taobao.arthas + arthas-vmtool + ${project.version} + com.alibaba bytekit-core 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 index 6f7dd468d..0928e12b3 100644 --- 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 @@ -1,6 +1,8 @@ package com.taobao.arthas.core.command.monitor200; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.lang.instrument.Instrumentation; import java.security.CodeSource; import java.util.ArrayList; @@ -11,6 +13,7 @@ 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.IOUtils; import com.taobao.arthas.common.VmToolUtils; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.express.Express; @@ -246,6 +249,25 @@ public class VmToolCommand extends AnnotatedCommand { if (libPath == null) { libPath = defaultLibPath; } + + // 尝试把lib文件复制到临时文件里,避免多次attach时出现 Native Library already loaded in another classloader + FileOutputStream tmpLibOutputStream = null; + FileInputStream libInputStream = null; + try { + File tmpLibFile = File.createTempFile(VmTool.JNI_LIBRARY_NAME, null); + tmpLibOutputStream = new FileOutputStream(tmpLibFile); + libInputStream = new FileInputStream(new File(libPath)); + + IOUtils.copy(libInputStream, tmpLibOutputStream); + libPath = tmpLibFile.getAbsolutePath(); + logger.debug("copy {} to {}", libPath, tmpLibFile); + } catch (Throwable e) { + logger.error("try to copy lib error! libPath: {}", libPath, e); + } finally { + IOUtils.close(libInputStream); + IOUtils.close(tmpLibOutputStream); + } + vmTool = VmTool.getInstance(libPath); } return vmTool; diff --git a/spy/src/main/java/arthas/VmTool.java b/spy/src/main/java/arthas/VmTool.java deleted file mode 100644 index 4e2775648..000000000 --- a/spy/src/main/java/arthas/VmTool.java +++ /dev/null @@ -1,111 +0,0 @@ -package arthas; - -/** - * @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(); - - private static synchronized native void forceGc0(); - - /** - * 获取某个class在jvm中当前所有存活实例 - */ - private static synchronized native T[] getInstances0(Class klass, int limit); - - /** - * 统计某个class在jvm中当前所有存活实例的总占用内存,单位:Byte - */ - private static synchronized native long sumInstanceSize0(Class klass); - - /** - * 获取某个实例的占用内存,单位:Byte - */ - private static native long getInstanceSize0(Object instance); - - /** - * 统计某个class在jvm中当前所有存活实例的总个数 - */ - private static synchronized native long countInstances0(Class klass); - - /** - * 获取所有已加载的类 - * @param klass 这个参数必须是 Class.class - * @return - */ - private static synchronized native Class[] getAllLoadedClasses0(Class klass); - - @Override - public void forceGc() { - forceGc0(); - } - - @Override - public T[] getInstances(Class klass) { - return getInstances0(klass, -1); - } - - @Override - public T[] getInstances(Class klass, int limit) { - if (limit == 0) { - throw new IllegalArgumentException("limit can not be 0"); - } - return getInstances0(klass, limit); - } - - @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 Class[] getAllLoadedClasses() { - return getAllLoadedClasses0(Class.class); - } - -} diff --git a/spy/src/main/java/arthas/VmToolMXBean.java b/spy/src/main/java/arthas/VmToolMXBean.java deleted file mode 100644 index f21000115..000000000 --- a/spy/src/main/java/arthas/VmToolMXBean.java +++ /dev/null @@ -1,53 +0,0 @@ -package arthas; - -/** - * 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 { - - /** - * https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#ForceGarbageCollection - */ - public void forceGc(); - - public T[] getInstances(Class klass); - - /** - * 获取某个class在jvm中当前所有存活实例 - * @param - * @param klass - * @param limit 如果小于 0 ,则不限制 - * @return - */ - public T[] getInstances(Class klass, int limit); - - /** - * 统计某个class在jvm中当前所有存活实例的总占用内存,单位:Byte - */ - public long sumInstanceSize(Class klass); - - /** - * 获取某个实例的占用内存,单位:Byte - */ - public long getInstanceSize(Object instance); - - /** - * 统计某个class在jvm中当前所有存活实例的总个数 - */ - public long countInstances(Class klass); - - /** - * 获取所有已加载的类 - */ - public Class[] getAllLoadedClasses(); -} diff --git a/spy/src/main/java/arthas/package-info.java b/spy/src/main/java/arthas/package-info.java deleted file mode 100644 index 8762944ed..000000000 --- a/spy/src/main/java/arthas/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/** - *
- * copy from arthas-vmtool/src/main/java 。
- * 因为动态链接库只能被加载一次,只能使用一份代码。放在spy jar里保证只有一份。
- * TODO 当arthas本身版本升级时,已append 到bootstrap classloader的spy jar不能升级,VmTool的接口可以会调用失败。
- * 
- */ -package arthas;