JPDA 架构研究13 - Agent利用环境指针访问VM(类管理篇)

引入:java

上文中提到Agent如何利用环境指针访问VM的(Watch)功能,这里主要讲解如何去管理类的。数组


分类9:管理类jvm

a.GetLoadedClasses. 得到虚拟机中全部被加载的类的数组。ide

jvmtiError
GetLoadedClasses(jvmtiEnv* env,
            jint* class_count_ptr,
              jclass** classes_ptr)

从返回值能够看出,class_count_ptr表示被加载的类的数量,classes_ptr表示类的数组列表。spa

注意,这里不包含内置类型对应的包装器类。好比说java.lang.Integer.TYPE就不包含在此列表中。线程


b.GetClassLoaderClasses.获取虚拟机中全部的Classloader所管理的类。debug

jvmtiError
GetClassLoaderClasses(jvmtiEnv* env,
            jobject initiating_loader,
            jint* class_count_ptr,
            jclass** classes_ptr)


c.GetClassSignature.获取某类的签名指针

jvmtiError
GetClassSignature(jvmtiEnv* env,
            jclass klass,
            char** signature_ptr,
            char** generic_ptr)

这里的签名是用的JNI类型签名方式,好比说java.util.List 的类签名是 "Ljava/util/List;"  而 int[] 的类签名是 "[I"code


d.GetClassStatus.获取类状态对象

jvmtiError
GetClassStatus(jvmtiEnv* env,
            jclass klass,
            jint* status_ptr)

类的有以下状态,分别用状态标志位来表示:

JVMTI_CLASS_STATUS_VERIFIED 1 类的字节码已经被修改
JVMTI_CLASS_STATUS_PREPARED 2 类准备状态已经完成 
JVMTI_CLASS_STATUS_INITIALIZED 4 类初始化完毕,静态初始化块已运行 S
JVMTI_CLASS_STATUS_ERROR 8 类初始化错误,所以不可以使用。 
JVMTI_CLASS_STATUS_ARRAY 16 类是个数组
JVMTI_CLASS_STATUS_PRIMITIVE 32  类是个原子类(好比 java.lang.Integer.TYPE).    


e.GetSourceFileName.获取指定类的源代码文件名

jvmtiError
GetSourceFileName(jvmtiEnv* env,
            jclass klass,
            char** source_name_ptr)


f.GetClassModifiers.获取类的访问修饰符

jvmtiError
GetClassModifiers(jvmtiEnv* env,
            jclass klass,
            jint* modifiers_ptr)

通常类的访问修饰符就是 public/private/protected ,另外还有final.

另外,若是类是原子类(好比java.lang.Integer.TYPE),则它的访问修饰符一定是public final.而且必定没有对应的interface.


g.GetClassMethods.获取类的方法列表。

jvmtiError
GetClassMethods(jvmtiEnv* env,
            jclass klass,
            jint* method_count_ptr,
            jmethodID** methods_ptr)

按照约定,分别返回方法数量以及方法的列表。注意,这个方法列表还包括构造器和静态初始块。


h.GetClassFields.获取类的字段列表。

jvmtiError
GetClassFields(jvmtiEnv* env,
            jclass klass,
            jint* field_count_ptr,
            jfieldID** fields_ptr)

注意,这个字段列表只包含直接声明的字段,不包含它从父类中继承过来的字段。字段的返回顺序精确的等同于在类文件中声明的顺序。


i.GetImplementedInterfaces.获取类所实现的接口

jvmtiError
GetImplementedInterfaces(jvmtiEnv* env,
            jclass klass,
            jint* interface_count_ptr,
            jclass** interfaces_ptr)

注意,对于类来讲,这里只返回它直接implements XXX,XXX的接口。

对于接口来讲,这里返回它 extends XXX的接口。


j.IsInterface.判断某类是不是一个接口

jvmtiError
IsInterface(jvmtiEnv* env,
            jclass klass,
            jboolean* is_interface_ptr)


k.IsArrayClass.判断某类是不是一个数组类

jvmtiError
IsArrayClass(jvmtiEnv* env,
            jclass klass,
            jboolean* is_array_class_ptr)


l.GetClassLoader.获取某类对应的类加载器的引用。

jvmtiError
GetClassLoader(jvmtiEnv* env,
            jclass klass,
            jobject* classloader_ptr)


m.GetSourceDebugExtension.获取类的debug扩展信息。

jvmtiError
GetSourceDebugExtension(jvmtiEnv* env,
            jclass klass,
            char** source_debug_extension_ptr)


n.RedefineClasses.从新定义一组类 (强大的热交换技术)

typedef struct {
    jclass klass;
    jint class_byte_count;
    const unsigned char* class_bytes;
} jvmtiClassDefinition;
jvmtiError
RedefineClasses(jvmtiEnv* env,
            jint class_count,
            const jvmtiClassDefinition* class_definitions)

这功能挺有趣,由于若是指定的字节码,则从新定义某类。因此该方法经过传入一组字节码来从新定义一组类。从新定义某类以后,对于该类会有以下一些改变:

(1).线程无需被挂起。

(2).类中的全部断点都被清除。

(3).全部属性都被更新。(注意,这里的属性是class对象的属性,不是类文件中的属性,那个叫字段field)

(4).类的已有的全部实例,其在堆上的ID都不受影响,其含有的字段值都不受影响。

另外,对于类的从新定义,也有些约束:

(1)重定义能够改变方法体,常量池,字段。

(2)重定义不能够添加/修改/删除任何类中的方法和字段。

(3)重定义不能够修改方法签名,改变访问修饰符和继承关系。

相关文章
相关标签/搜索