From 15f7844b4f848b2f4b23af2a85cedac251c9cff8 Mon Sep 17 00:00:00 2001 From: hengyunabc Date: Tue, 27 Apr 2021 00:42:48 +0800 Subject: [PATCH] refactor Vmtool, support singleton, support VMtoolMXBean. #1781 --- .../src/main/java/arthas/VMtoolMXBean.java | 48 +++++++++++++++++++ .../src/main/java/arthas/Vmtool.java | 46 ++++++++++++++---- .../src/main/native/include/arthas_Vmtool.h | 2 +- .../src/main/native/src/jni-library.cpp | 12 ++--- .../src/test/java/arthas/VmtoolTest.java | 14 +++--- 5 files changed, 100 insertions(+), 22 deletions(-) create mode 100644 arthas-vmtool/src/main/java/arthas/VMtoolMXBean.java diff --git a/arthas-vmtool/src/main/java/arthas/VMtoolMXBean.java b/arthas-vmtool/src/main/java/arthas/VMtoolMXBean.java new file mode 100644 index 000000000..537a081a0 --- /dev/null +++ b/arthas-vmtool/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/arthas-vmtool/src/main/java/arthas/Vmtool.java b/arthas-vmtool/src/main/java/arthas/Vmtool.java index 3430ae95b..1f0c21ab3 100644 --- a/arthas-vmtool/src/main/java/arthas/Vmtool.java +++ b/arthas-vmtool/src/main/java/arthas/Vmtool.java @@ -7,7 +7,7 @@ import java.util.ArrayList; * @author hengyunabc 2021-04-26 * @since 3.5.1 */ -public class Vmtool { +public class Vmtool implements VMtoolMXBean { /** * 不要修改jni-lib的名称 @@ -41,39 +41,69 @@ public class Vmtool { /** * 检测jni-lib是否正常,如果正常,应该输出OK */ - public static native String check(); + private static native String check0(); /** * 获取某个class在jvm中当前所有存活实例 */ - public static native ArrayList getInstances(Class klass); + private static native ArrayList getInstances0(Class klass); /** * 统计某个class在jvm中当前所有存活实例的总占用内存,单位:Byte */ - public static native long sumInstanceSize(Class klass); + private static native long sumInstanceSize0(Class klass); /** * 获取某个实例的占用内存,单位:Byte */ - public static native long getInstanceSize(Object instance); + private static native long getInstanceSize0(Object instance); /** * 统计某个class在jvm中当前所有存活实例的总个数 */ - public static native long countInstances(Class klass); + private static native long countInstances0(Class klass); /** * 获取所有已加载的类 */ - public static native ArrayList> getAllLoadedClasses(); + private static native ArrayList> getAllLoadedClasses0(); /** * 包括小类型(如int) */ @SuppressWarnings("all") public static ArrayList getAllClasses() { - return getInstances(Class.class); + 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/arthas-vmtool/src/main/native/include/arthas_Vmtool.h b/arthas-vmtool/src/main/native/include/arthas_Vmtool.h index 903c47405..2d03330c5 100644 --- a/arthas-vmtool/src/main/native/include/arthas_Vmtool.h +++ b/arthas-vmtool/src/main/native/include/arthas_Vmtool.h @@ -12,7 +12,7 @@ extern "C" { * Method: check * Signature: ()Ljava/lang/String; */ -JNIEXPORT jstring JNICALL Java_arthas_Vmtool_check +JNIEXPORT jstring JNICALL Java_arthas_Vmtool_check0 (JNIEnv *, jclass); /* diff --git a/arthas-vmtool/src/main/native/src/jni-library.cpp b/arthas-vmtool/src/main/native/src/jni-library.cpp index 2e81b183c..d140541a5 100644 --- a/arthas-vmtool/src/main/native/src/jni-library.cpp +++ b/arthas-vmtool/src/main/native/src/jni-library.cpp @@ -6,7 +6,7 @@ extern "C" JNIEXPORT jstring JNICALL -Java_arthas_Vmtool_check(JNIEnv *env, jclass thisClass) { +Java_arthas_Vmtool_check0(JNIEnv *env, jclass thisClass) { return env->NewStringUTF("OK"); } @@ -47,7 +47,7 @@ HeapObjectCallback(jlong class_tag, jlong size, jlong *tag_ptr, void *user_data) extern "C" JNIEXPORT jobject JNICALL -Java_arthas_Vmtool_getInstances(JNIEnv *env, jclass thisClass, jclass klass) { +Java_arthas_Vmtool_getInstances0(JNIEnv *env, jclass thisClass, jclass klass) { jvmtiEnv *jvmti = getJvmtiEnv(env); @@ -88,7 +88,7 @@ Java_arthas_Vmtool_getInstances(JNIEnv *env, jclass thisClass, jclass klass) { extern "C" JNIEXPORT jlong JNICALL -Java_arthas_Vmtool_sumInstanceSize(JNIEnv *env, jclass thisClass, jclass klass) { +Java_arthas_Vmtool_sumInstanceSize0(JNIEnv *env, jclass thisClass, jclass klass) { jvmtiEnv *jvmti = getJvmtiEnv(env); @@ -126,7 +126,7 @@ Java_arthas_Vmtool_sumInstanceSize(JNIEnv *env, jclass thisClass, jclass klass) } extern "C" -JNIEXPORT jlong JNICALL Java_arthas_Vmtool_getInstanceSize +JNIEXPORT jlong JNICALL Java_arthas_Vmtool_getInstanceSize0 (JNIEnv *env, jclass thisClass, jobject instance) { jvmtiEnv *jvmti = getJvmtiEnv(env); @@ -142,7 +142,7 @@ JNIEXPORT jlong JNICALL Java_arthas_Vmtool_getInstanceSize extern "C" JNIEXPORT jlong JNICALL -Java_arthas_Vmtool_countInstances(JNIEnv *env, jclass thisClass, jclass klass) { +Java_arthas_Vmtool_countInstances0(JNIEnv *env, jclass thisClass, jclass klass) { jvmtiEnv *jvmti = getJvmtiEnv(env); @@ -172,7 +172,7 @@ Java_arthas_Vmtool_countInstances(JNIEnv *env, jclass thisClass, jclass klass) { } extern "C" -JNIEXPORT jobject JNICALL Java_arthas_Vmtool_getAllLoadedClasses +JNIEXPORT jobject JNICALL Java_arthas_Vmtool_getAllLoadedClasses0 (JNIEnv *env, jclass thisClass) { jvmtiEnv *jvmti = getJvmtiEnv(env); diff --git a/arthas-vmtool/src/test/java/arthas/VmtoolTest.java b/arthas-vmtool/src/test/java/arthas/VmtoolTest.java index 915e0d54b..fe1592557 100644 --- a/arthas-vmtool/src/test/java/arthas/VmtoolTest.java +++ b/arthas-vmtool/src/test/java/arthas/VmtoolTest.java @@ -28,27 +28,27 @@ public class VmtoolTest { System.err.println(path); String libPath = new File(path, System.mapLibraryName(Vmtool.JNI_LIBRARY_NAME)).getAbsolutePath(); - Vmtool.getInstance(libPath); + Vmtool vmtool = Vmtool.getInstance(libPath); //调用native方法,获取已加载的类,不包括小类型(如int) - ArrayList> allLoadedClasses = Vmtool.getAllLoadedClasses(); + ArrayList> allLoadedClasses = vmtool.getAllLoadedClasses(); System.out.println("allLoadedClasses->" + allLoadedClasses.size()); //通过下面的例子,可以看到getInstances(Class klass)拿到的是当前存活的所有对象 WeakReference weakReference1 = new WeakReference(new VmtoolTest()); WeakReference weakReference2 = new WeakReference(new VmtoolTest()); System.out.println(weakReference1.get() + " " + weakReference2.get()); - ArrayList beforeInstances = Vmtool.getInstances(Vmtool.class); + ArrayList beforeInstances = vmtool.getInstances(Vmtool.class); System.out.println("before instances->" + beforeInstances); - System.out.println("size->" + Vmtool.getInstanceSize(weakReference1.get())); - System.out.println("count->" + Vmtool.countInstances(Vmtool.class)); - System.out.println("sum size->" + Vmtool.sumInstanceSize(Vmtool.class)); + System.out.println("size->" + vmtool.getInstanceSize(weakReference1.get())); + System.out.println("count->" + vmtool.countInstances(Vmtool.class)); + System.out.println("sum size->" + vmtool.sumInstanceSize(Vmtool.class)); beforeInstances = null; System.gc(); Thread.sleep(100); System.out.println(weakReference1.get() + " " + weakReference2.get()); - ArrayList afterInstances = Vmtool.getInstances(Vmtool.class); + ArrayList afterInstances = vmtool.getInstances(Vmtool.class); System.out.println("after instances->" + afterInstances); } catch (Exception e) { e.printStackTrace();