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)重定義不能夠修改方法簽名,改變訪問修飾符和繼承關係。

相關文章
相關標籤/搜索