vmtool lib support reload/reattach.

pull/1784/head
hengyunabc 4 years ago
parent 14d7efab1e
commit 32e7bfa6b8

@ -121,7 +121,7 @@
<linkerStartOption>-o</linkerStartOption> <linkerStartOption>-o</linkerStartOption>
</linkerStartOptions> </linkerStartOptions>
<linkerEndOptions> <linkerEndOptions>
<linkerEndOption>-o ${project.build.directory}/classes/${lib_name}</linkerEndOption> <linkerEndOption>-o ${project.build.directory}/${lib_name}</linkerEndOption>
</linkerEndOptions> </linkerEndOptions>
</configuration> </configuration>
<executions> <executions>

@ -36,11 +36,6 @@ public class VmTool implements VmToolMXBean {
return instance; return instance;
} }
/**
* jni-libOK
*/
private static native String check0();
private static synchronized native void forceGc0(); private static synchronized native void forceGc0();
/** /**

@ -1,6 +1,2 @@
/**
* <pre>
* spy/src/main/java
* </pre>
*/
package arthas; package arthas;

@ -10,12 +10,16 @@ import org.junit.Test;
import com.taobao.arthas.common.VmToolUtils; import com.taobao.arthas.common.VmToolUtils;
import arthas.VmToolTest.LimitTest;
/** /**
* jvm-Xms128m -Xmx128m * jvm-Xms128m -Xmx128m
*/ */
public class VmToolTest { 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 * 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 @Test
public void testGetInstancesMemoryLeak() { public void testGetInstancesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程 //这里睡20s是为了方便用jprofiler连接上进程

@ -120,6 +120,11 @@
<artifactId>arthas-common</artifactId> <artifactId>arthas-common</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-vmtool</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>bytekit-core</artifactId> <artifactId>bytekit-core</artifactId>

@ -1,6 +1,8 @@
package com.taobao.arthas.core.command.monitor200; package com.taobao.arthas.core.command.monitor200;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.security.CodeSource; import java.security.CodeSource;
import java.util.ArrayList; 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.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.common.IOUtils;
import com.taobao.arthas.common.VmToolUtils; import com.taobao.arthas.common.VmToolUtils;
import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.express.Express; import com.taobao.arthas.core.command.express.Express;
@ -246,6 +249,25 @@ public class VmToolCommand extends AnnotatedCommand {
if (libPath == null) { if (libPath == null) {
libPath = defaultLibPath; 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); vmTool = VmTool.getInstance(libPath);
} }
return vmTool; return vmTool;

@ -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-libOK
*/
private static native String check0();
private static synchronized native void forceGc0();
/**
* classjvm
*/
private static synchronized native <T> T[] getInstances0(Class<T> klass, int limit);
/**
* classjvmByte
*/
private static synchronized native long sumInstanceSize0(Class<?> klass);
/**
* Byte
*/
private static native long getInstanceSize0(Object instance);
/**
* classjvm
*/
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> T[] getInstances(Class<T> klass) {
return getInstances0(klass, -1);
}
@Override
public <T> T[] getInstances(Class<T> 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);
}
}

@ -1,53 +0,0 @@
package arthas;
/**
* VmTool interface for JMX server. How to register VmTool MBean:
*
* <pre>
* {@code
* ManagementFactory.getPlatformMBeanServer().registerMBean(
* VmTool.getInstance(),
* new ObjectName("arthas:type=VmTool")
* );
* }
* </pre>
* @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> T[] getInstances(Class<T> klass);
/**
* classjvm
* @param <T>
* @param klass
* @param limit 0
* @return
*/
public <T> T[] getInstances(Class<T> klass, int limit);
/**
* classjvmByte
*/
public long sumInstanceSize(Class<?> klass);
/**
* Byte
*/
public long getInstanceSize(Object instance);
/**
* classjvm
*/
public long countInstances(Class<?> klass);
/**
*
*/
public Class<?>[] getAllLoadedClasses();
}

@ -1,8 +0,0 @@
/**
* <pre>
* copy from arthas-vmtool/src/main/java
* 使spy jar
* TODO arthasappend bootstrap classloaderspy jarVmTool
* </pre>
*/
package arthas;
Loading…
Cancel
Save