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