天天看點

Java 虛拟機監視程式接口 (JVMPI)【轉載】

Java 虛拟機監視程式接口 (JVMPI)

--------------------------------------------------------------------------------

本文檔介紹了 JDK 1.2 中的 Java 虛拟機監視程式接口(JVMPI)。它适合于有意用 Sun 的 Java 虛拟機實作來開發監視程式的工具廠商。 

注意:該接口是 JDK 1.2 最終版中的試驗性功能。JVMPI 尚未成為标準的監視程式接口。考慮到那些在 Java 虛拟機中急需監視程式鈎子的工具廠商,我們編寫了本文檔。JVMPI 将根據客戶和工具廠商的意見而不斷改進。如有意見,請發送到:[email protected]. 

目錄
概述 
啟動 
函數調用接口 
事件通知 
JVMPI 辨別符 
線程和鎖定問題 
監視程式代理和前端間的資料通信 
接口函數 
CreateSystemThread 
DisableEvent 
DisableGC 
EnableEvent 
EnableGC 
GetCallTrace 
GetCurrentThreadCpuTime 
GetMethodClass 
GetThreadLocalStorage 
GetThreadObject 
GetThreadStatus 
NotifyEvent 
ProfilerExit 
RawMonitorCreate 
RawMonitorDestroy 
RawMonitorEnter 
RawMonitorExit 
RawMonitorNotifyAll 
RawMonitorWait 
RequestEvent 
ResumeThread 
RunGC 
SetThreadLocalStorage 
SuspendThread 
ThreadHasRun 
事件 
JVMPI_EVENT_ARENA_DELETE 
JVMPI_EVENT_ARENA_NEW 
JVMPI_EVENT_CLASS_LOAD 
JVMPI_EVENT_CLASS_LOAD_HOOK 
JVMPI_EVENT_CLASS_UNLOAD 
JVMPI_EVENT_COMPILED_METHOD_LOAD 
JVMPI_EVENT_COMPILED_METHOD_UNLOAD 
JVMPI_EVENT_DATA_DUMP_REQUEST 
JVMPI_EVENT_DATA_RESET_REQUEST 
JVMPI_EVENT_GC_FINISH 
JVMPI_EVENT_GC_START 
JVMPI_EVENT_HEAP_DUMP 
JVMPI_EVENT_JNI_GLOBALREF_ALLOC 
JVMPI_EVENT_JNI_GLOBALREF_FREE 
JVMPI_EVENT_JNI_WEAK_GLOBALREF_ALLOC 
JVMPI_EVENT_JNI_WEAK_GLOBALREF_FREE 
JVMPI_EVENT_JVM_INIT_DONE 
JVMPI_EVENT_JVM_SHUT_DOWN 
JVMPI_EVENT_METHOD_ENTRY 
JVMPI_EVENT_METHOD_ENTRY2 
JVMPI_EVENT_METHOD_EXIT 
JVMPI_EVENT_MONITOR_CONTENDED_ENTER 
JVMPI_EVENT_MONITOR_CONTENDED_ENTERED 
JVMPI_EVENT_MONITOR_CONTENDED_EXIT 
JVMPI_EVENT_MONITOR_DUMP 
JVMPI_EVENT_MONITOR_WAIT 
JVMPI_EVENT_MONITOR_WAITED 
JVMPI_EVENT_OBJECT_ALLOC 
JVMPI_EVENT_OBJECT_DUMP 
JVMPI_EVENT_OBJECT_FREE 
JVMPI_EVENT_OBJECT_MOVE 
JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTER 
JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTERED 
JVMPI_EVENT_RAW_MONITOR_CONTENDED_EXIT 
JVMPI_EVENT_THREAD_END 
JVMPI_EVENT_THREAD_START 
轉儲格式 
轉儲格式描述中使用的大小和類型 
堆轉儲格式 
對象轉儲格式 
監控器轉儲格式 
資料類型 
jobjectID 
JVMPI_CallFrame 
JVMPI_CallTrace 
JVMPI_Field 
JVMPI_HeapDumpArg 
JVMPI_Lineno 
JVMPI_Method 
JVMPI_RawMonitor 
有關 JDK1.2 實作局限性的說明 

--------------------------------------------------------------------------------


1. 概述
JVMPI 是 Java 虛拟機和程序中監視程式代理之間的雙向函數調用接口。一方面,虛拟機将通知不同僚件的監視程式代理(例如相應的堆配置設定、線程啟動等)。另一方面,監視程式代理也通過 JVMPI 發送控制并請求更多的資訊。例如,監視程式代理能夠根據監視程式前端的需要,打開/關閉特定事件通知。 

 

監視程式前端可以與監視程式代理在相同的程序中運作,也可在不同的程序中運作。它可以駐留在同一機器的不同程序中,或者通過網絡駐留在遠端計算機中。JVMPI 沒有指定标準通信協定。工具廠商可以根據不同監視程式前端的需要而設計适當的通信協定。 

基于 JVMPI 的監視程式工具能擷取多種資訊,例如用于綜合性能分析的堆記憶體配置設定址、CPU 使用熱點、不必要的對象保持及監控器競争。 

JVMPI 支援部分監視程式,即使用者可有選擇地對虛拟機正常運作時間的子集進行應用程式的監視,并可選擇僅獲得特定類型的監視程式資訊。 

目前的 JVMPI 版本中對每個虛拟機僅支援一個代理。 

1.1. 啟動
使用者可以通過 Java 虛拟機的指令行選項指定監視程式代理名和監視程式代理選項。例如,假定使用者指定: 

    java -Xrunmyprofiler:heapdump=on,file=log.txt ToBeProfiledClass
則 VM 試圖在 Java 的庫目錄中定位名為 myprofiler 的監視程式代理庫: 

在 Win32 中,它是 $JAVA_HOME\bin\myprofiler.dll 
在 SPARC/Solaris 中,它是 $JAVA_HOME/lib/sparc/libmyprofiler.so 
如果在 Java 庫目錄中找不到該庫,則虛拟機将遵循給定平台的正常庫搜尋機制繼續搜尋該庫: 

在 Win32 中,虛拟機将搜尋目前目錄、 Windows 系統目錄和 PATH 環境變量中的目錄。 
在 Solaris 中,虛拟機将搜尋 LD_LIBRARY_PATH 中的目錄。 
虛拟機加載監視程式的代理庫并尋找以下入口點: 

jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved);

虛拟機調用 JVM_OnLoad 函數,将 JavaVM 執行個體指針作為第一個參數,然後将字元串 "heapdump=on,file=log.txt" 作為第二個參數。JVM_OnLoad 的第三個參數将被保留并設定為 NULL。 

成功後,JVM_OnLoad 函數傳回 JNI_OK。如果因為某些原因 JVM_OnLoad 函數失敗,則将傳回 JNI_ERR。 

1.2. 函數調用接口
監視程式代理将通過對 JavaVM 指針發出 GetEnv 調用來獲得函數調用接口。例如,下面的代碼檢索在 JDK 1.2 中實作的 JVMPI 接口: 

JVMPI_Interface *jvmpi_interface;

JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved)
{
    int res = (*jvm)->GetEnv(jvm, (void **)&jvmpi_interface, JVMPI_VERSION_1);
    if (res <0) { return JNI_ERR; } ... /* 使用 jvmpi_interface 中的項*/ } 

JVMPI_Interface 結構定義了監視程式代理和虛拟機之間的函數調用接口:


/* 接口函數 */
typedef struct {
    jint version;   /* JVMPI 版*/

    /* ------監視程式實作的接口------ */

    void (*NotifyEvent)(JVMPI_Event *event);

    /* ------ JVM 實作的接口------ */

    jint (*EnableEvent)(jint event_type, void *arg);
    jint (*DisableEvent)(jint event_type, void *arg);
    jint (*RequestEvent)(jint event_type, void *arg);

    void (*GetCallTrace)(JVMPI_CallTrace *trace, jint depth);

    void (*ProfilerExit)(jint);

    JVMPI_RawMonitor (*RawMonitorCreate)(char *lock_name);
    void (*RawMonitorEnter)(JVMPI_RawMonitor lock_id);
    void (*RawMonitorExit)(JVMPI_RawMonitor lock_id);
    void (*RawMonitorWait)(JVMPI_RawMonitor lock_id, jlong ms);
    void (*RawMonitorNotifyAll)(JVMPI_RawMonitor lock_id);
    void (*RawMonitorDestroy)(JVMPI_RawMonitor lock_id);


    jlong (*GetCurrentThreadCpuTime)(void);
    void (*SuspendThread)(JNIEnv *env);
    void (*ResumeThread)(JNIEnv *env);
    jint (*GetThreadStatus)(JNIEnv *env);
    jboolean (*ThreadHasRun)(JNIEnv *env);
    jint (*CreateSystemThread)(char *name, jint priority, void (*f)(void *));
    void (*SetThreadLocalStorage)(JNIEnv *env_id, void *ptr);
    void * (*GetThreadLocalStorage)(JNIEnv *env_id);

    void (*DisableGC)(void);
    void (*EnableGC)(void);
    void (*RunGC)(void);

    jobjectID (*GetThreadObject)(JNIEnv *env);
    jobjectID (*GetMethodClass)(jmethodID mid);
} JVMPI_Interface;

GetEnv 函數傳回 JVMPI_Interface 的指針,其 version 域訓示 JVMPI 版本與 GetEnv 調用中所傳遞的版
本号參數是相容的。注意 version 域的值不必與 GetEnv 調用中傳遞的版本參數相同。


GetEnv 傳回的 JVMPI_Interface 将設定除 NotifyEvent 函數之外的所有函數。監視程式代理在從 JVM_OnLoad 傳回前必須設定 NotifyEvent 函數指針。 

1.3. 事件通知
虛拟機将通過用 JVMPI_Event 資料結構作為參數調用 NotifyEvent 來發送事件。它支援下列事件: 

方法進入和退出 
對象配置設定、移動和釋放 
堆塊建立和删除 
GC 啟動和完成 
JNI 全局引用配置設定和釋放 
JNI 弱全局引用配置設定和釋放 
編譯方法的加載和解除安裝 
線程啟動和結束 
為使用機器準備類檔案資料 
類加載和解除安裝 
競争的 Java 監控器等待進入、已進入和退出 
競争的原監控器等待進入、已進入和退出 
Java 監控器等待和被等待 
監控器轉儲 
堆轉儲 
對象轉儲 
請求轉儲或重置監視程式資料 
Java 虛拟機初始化和關閉 
JVMPI_Event 結構包含事件類型、目前線程的 JNIEnv 指針及其他事件特定資訊。事件特定資訊用特定事件結構的聯合來表示。JVMPI 事件一節提供了所有事件特定結構的完整介紹。現在,我們将顯示類加載和類解除安裝的事件特定結構。 

typedef struct {
    jint event_type;                  /* event_type  */
    JNIEnv *env_id;                   /* 事件發生地點的 env  */

    union {
        struct {
	    char *class_name;         /* 類名 */
	    char *source_name;        /* 源檔案名 */
	    jint num_interfaces;      /* 實作的接口數 */
  	    jint num_methods;         /* 類中的方法數 */
	    JVMPI_Method *methods;    /* 方法 */
	    jint num_static_fields;   /* 靜态域數 */
	    JVMPI_Field *statics;     /* 靜态域 */
	    jint num_instance_fields; /*執行個體域數 */
	    JVMPI_Field *instances;   /* 執行個體域 */
	    jobjectID class_id;       /* 類對象辨別符 */
	} class_load;

        struct {
	    jobjectID class_id;       /* 類對象辨別符 */
	} class_unload;

        ... /* 要擷取完整的清單,參見 JVMPI 事件一節 */
    } u;
} JVMPI_Event;


1.4. JVMPI 辨別符
JVMPI 将 Java 虛拟機中的實體視作不同類型的辨別符。線程、類、方法、對象、堆塊和 JNI 全局引用都具有唯一的辨別符。 

每個辨別符具有定義事件和未定義事件。定義事件提供辨別符的相關資訊。例如,線程辨別符的定義事件包含有線程名和其他項。 

标志符在未定義事件到達之前将一直有效。未定義事件使辨別符無效,其值以後可作為其它類型的辨別符。例如,線程辨別符值可以線上程終止後重定義為方法辨別符。 

辨別符 資料類型 定義事件 未定義事件 
線程辨別符 JNIEnv * 線程啟動 線程結束 
對象辨別符 jobjectID 對象配置設定 對象釋放、對象移動 和塊删除 
類辨別符 jobjectID 類加載 類解除安裝和對象移動 
方法辨別符 jmethodID 定義類加載 定義類解除安裝 
塊辨別符 jint 建立塊 删除塊 
JNI 全局引用辨別符 jobject 全局引用配置設定 全局引用釋放 

假定在監視程式初始化期間啟用定義事件,則應保證明體在其它 JVMPI 事件中出現前通過定義事件将實體的建立通知給監視程式代理。 

如果定義事件沒有啟用,監視程式代理将會接收未知辨別符。這種情況下,監視程式代理可能發出 RequestEvent 調用,請求發送相應的定義事件。 

代表對象的辨別符具有 jobjectID 類型。類由相應 java.lang.Class 對象的對象辨別符表示。是以,類辨別符也具有 jobjectID 類型。 

jobjectID 由 object alloc 事件定義,并在對象所配置設定的塊中保持有效,直到其未定義事件發生: 

對象釋放事件使對象辨別符無效。 
對象移動事件是一種特殊的未定義事件。與其它訓示相應實體終止的未定義事件不同,對象将仍然存在,但其辨別符發生改變,并且可能被移動到新塊中。 
删除塊事件使所有塊中保留的對象辨別符無效。 
當對象釋放或删除塊事件使對象辨別符無效時,該對象即“被作為垃圾收集”。 

一般而言,監視程式代理維持 jobjectID 及其對象辨別符的内部表示之間的映像,并更新相應的 JVMPI 對象辨別符映像。 

由于對象辨別符在 GC 期間可以失效,是以虛拟機發出所有含有禁用 GC 的 jobjectID 項的事件。另外,監視程式代理在直接操作 jobjectID 資料類型時必須禁止 GC。否則,GC 會在代理代碼中操作 jobjectID 時使它無效。監視程式代理将確定在調用接受 jobjectID 參數或者傳回 jobjectID 結果的 JVMPI 函數時禁用 GC。如果函數調用處于已經禁用 GC 的事件處理程式内,則監視程式代理可不必顯式地再次禁用 GC。 

線程可由 JNIEnv 接口指針或相應 java.lang.Thread 對象的對象辨別符所辨別。JNIEnv 指針将線上程啟動和線程結束事件之間有效,并線上程生命期内保持不變。另一方面,java.lang.Thread 對象辨別符線上程結束後仍能保持有效,直到它被作為垃圾收集。監視程式代理能夠通過調用 GetThreadObject 函數,将 JNIEnv 指針轉換為相應的線程對象辨別符。 

1.5. 線程和鎖定問題
JVMPI 由監視程式代理使用,後者與 Java 虛拟機在相同的程序中運作。編寫代理的程式員一定要仔細處理線程和鎖定問題,以防資料破壞和死鎖。 

事件将被發送到它們産生的同一線程中。例如,類加載事件将發送到加載該類的線程中。多個事件可同時在不同線程中發生。是以,代理程式必須提供必要的同步,以避免由于多個線程同時更新相同的資料結構而引起資料破壞。 

某些情況下,某些頻繁事件的同步(例如方法入口和方法出口)可能會給程式執行帶來過多的開支。代理可利用 JVMPI 提供的局部線程存儲支援來記錄監視程式資料,而無需與全局鎖競争,并且将隻在標明間隔将局部線程資料合并到全局監視程式中。JVMPI 可以為代理提供指針大小的局部線程存儲空間。下面是一個簡單的示例,示範了監視程式代理如何利用該功能。假定我們需要編寫監視程式代理來計算每個線程中執行的方法數。代理将安裝線程啟動、方法入口和線程結束事件的事件處理程式: 

/* 線程啟動事件處理程式
 * 設定局部線程方法調用計數器的存儲空間
 */
void ThreadStartHandler(JNIEnv *thread_id)
{
    int *p_ctr = (int *)malloc(sizeof(int));
    CALL(SetThreadLocalStorage)(thread_id, p_ctr);
}

/* 方法進入事件處理程式
 * 增量局部線程方法調用計數器 
 */
void MethodEntryHandler(jmethodID method_id, JNIEnv *thread_id)
{
    int *p_ctr = (int *)CALL(GetThreadLocalStorage)(thread_id);
    (*p_ctr)++;
}

/* 線程結束處理程式
 * 列印執行的方法數
 */
void ThreadEndHandler(JNIEnv *thread_id)
{
    int *p_ctr = (int *)CALL(GetThreadLocalStorage)(thread_id);
    fprintf(stdout, "Thread %x executed %d methods\n",
	    thread_id, (*p_ctr));
    free(p_ctr);
}

下面的 JVMPI 函數能使在函數執行期間在同一線程中同步發送事件通知: 

RequestEvent 
CreateSystemThread 
RunGC 
RequestEvent 函數提供監視程式代理顯式要求的 JVMPI 事件。CreateSystemThread 函數導緻發出對象配置設定和線程啟動事件。RunGC 函數可生成 GC 相關事件。 

當監視程式代理加載到 Java 虛拟機中後,該程序可能成為三種模型之一:支援 GC 的多線程模式、不支援 GC 的多線程模式及挂起的線程模式。不同的 JVMPI 事件以不同的模式釋出。某些 JVMPI 函數将程序從一種模式改變成另一種模式。 

為避免死鎖,監視程式代理必須遵守下列指導方針: 

在支援 GC 的多線程模式中,代理模式在獲得鎖定和調用 JVMPI 函數方面應具有很大的自由。當然,避免死鎖的正正常則仍然适用。不同的線程不能以不同的次序進入同一鎖定集。 
禁用 GC 後,代理程式不能調用任何要求建立新 Java 對象或使垃圾收集器運作的 JVMPI 函數。目前,此類函數包括 CreateSystemThread 和 RunGC。另外,程式員需要知道禁用 GC 将會線上程之間建立隐含鎖定依賴。當禁用 GC 時,目前的線程将不能安全獲得某些鎖定。舉例而言,如果線程禁用 GC 并試圖獲得鎖定,而其它線程已獲得該鎖定但又觸發了 GC,就可能會發生死鎖。 
線上程挂起模式裡,一個或多個線程已經挂起。這種情況下,代理程式不能執行任何引起目前線程阻塞的操作。此類操作包括由标準 C 庫提供的 malloc 和 fprintf 函數,它們通常可獲得由其中某一挂起線程保持的内部 C 庫鎖定。 

1.6 監視程式代理和前端間的資料通信。
JVMPI 為監視程式代理提供了一種低級機制來與虛拟機進行通信,目标是為根據前端需要而展示資料的監視程式代理提供最大的靈活性,同時保持虛拟機所做的處理工作量最小。是以,JVMPI 沒有指定監視程式與前端間的傳輸協定。作為替代,工具廠商可以自己設計适合前端需要的監視程式代理。 

當為了允許監視程式代理和前端駐留在不同的機器中而設計傳輸協定時,需要考慮下列問題: 

指針大小(例如 32 或 64 位)- 所有 JVMPI ID 均是指針類型(參見資料類型)。 
位元組順序(小 endian 或大 endian)。 
位順序(最重要的位在前,或者最不重要的位優先在前)。 
字元串編碼 - JVMPI 使用 Java 虛拟機規範中列出的 UTF-8 編碼。 
例如,與 JDK 1.2 版一起釋出的 hprof 監視程式代理将所有辨別符大小作為第一條記錄發送,并對整數和浮點資料使用标準網絡位元組順序。 

2. 接口函數

jint (*CreateSystemThread)(char *name, jint priority, void (*f)(void *));
由監視程式代理調用,用于在 Java 虛拟機中建立守護程序線程。 
隻有在 JVM 通知 JVMPI_EVENT_INIT_DONE 之後且系統處于支援 GC 的多線程模式中時,監視程式代碼進行該調用才是安全的。 

參數: 

name  - 線程名。  
priority  - 線程優先級;其值可以為:  
 JVMPI_NORMAL_PRIORITY 
JVMPI_MAXIMUM_PRIORITY 
JVMPI_MINIMUM_PRIORITY 
 
f  - 該線程運作的函數。  

傳回值: 

JNI_OK  - 成功。  
JNI_ERR  - 失敗。  


jint (*DisableEvent)(jint event_type, void *arg);
由監視程式代理調用,用于禁用特定類型事件的通知。與 event_type 不同,監視程式代理也可傳遞參數,後者将提供給定事件類型的特定附加資訊。 
虛拟機啟動時,所有事件均将被禁用。一旦啟用後,則在被顯式禁用前該事件将保持可用狀态。 

如果 event_type 為 JVMPI_EVENT_HEAP_DUMP、JVMPI_EVENT_MONITOR_DUMP 或 JVMPI_EVENT_OBJECT_DUMP,則該函數傳回 JVMPI_NOT_AVAILABLE。 

參數: 

event_type  - 事件類型, JVMPI_EVENT_CLASS_LOAD 等。  
arg  - 事件特定資訊。  

傳回值: 

JVMPI_SUCCESS  成功禁用。  
JVMPI_FAIL  禁用失敗。  
JVMPI_NOT_AVAILABLE  不能禁用給定的 event_type。  


void (*DisableGC)(void);
由監視程式調用,用于禁用垃圾收集功能,直到調用 EnabledGC。DisableGC 和 EnableGC 調用可以嵌套。 

jint (*EnableEvent)(jint event_type, void *arg);
由監視程式代理調用,用于啟用特定類型事件的通知。與 event_type 不同,監視程式也可以傳遞參數,後者可提供給定事件類型的特定附加資訊。 
虛拟機啟動時,所有事件君将被禁用。一旦啟用後,則在顯式禁用前事件将保持啟用狀态。 

如果 event_type 為 JVMPI_EVENT_HEAP_DUMP、JVMPI_EVENT_MONITOR_DUMP 或 JVMPI_EVENT_OBJECT_DUMP,則該函數傳回 JVMPI_NOT_AVAILABLE。監視程式代理必須使用 RequestEvent 函數來請求這些事件。 

參數: 

event_type  - 事件類型, JVMPI_EVENT_CLASS_LOAD 等。  
arg  - 事件特定參數。  

傳回值: 

JVMPI_SUCCESS  啟用成功。  
JVMPI_FAIL  啟用失敗。  
JVMPI_NOT_AVAILABLE  不能啟用給定的 event_type。  


void (*EnableGC)(void);
啟用垃圾收集。DisableGC 和 EnableGC 調用可以嵌套。 

void (*GetCallTrace)(JVMPI_CallTrace *trace, jint depth);
由監視程式調用,用于獲得給定線程的目前方法調用棧跟蹤。該線程由 JVMPI_CallTrace 結構中的 env_id 域辨別。監視程式代理應該為所請求的棧深度給 JVMPI_CallTrace 結構配置設定足夠的記憶體。虛拟機将填寫 frames 緩沖區和 num_frames 域。 
參數: 

trace  - 跟蹤由虛拟機填寫的資料結構。  
depth  - 調用棧跟蹤深度。  


jlong (*GetCurrentThreadCpuTime)(void);
由監視程式代理調用,用于獲得目前線程消耗的累積 CPU 時間。 
傳回值: 

以納秒計的時間  


jobjectID (*GetMethodClass)(jmethodID mid);
由監視程式代理調用,用于獲得定義方法的類的對象辨別符。 
監視程式在調用該函數前必須禁用 GC。 

參數: 

mid  -方法辨別符。  

傳回值: 

定義類的對象辨別符。  


void * (*GetThreadLocalStorage)(JNIEnv *env_id);
由監視程式調用,用于獲得 JVMPI 局部線程存儲值。JVMPI 将為代理提供指針大小的局部線程存儲空間,能用來記錄每個線程的監視程式資訊。 
參數: 

env_id  - 線程的 JNIEnv *。  

傳回值: 

局部線程存儲空間的值  


jobjectID (*GetThreadObject)(JNIEnv *env);
由監視程式代理調用,用于獲得相應于 JNIEnv 指針的線程對象辨別符。 
監視程式在調用該函數前必須禁用 GC。 

參數: 

env  - 線程的 JNIEnv 指針。  

傳回值: 

線程對象辨別符。  


jint (*GetThreadStatus)(JNIEnv *env);
由監視程式代理調用,用于獲得線程狀态。 
JVMPI 函數 SuspendThread 和 ResumeThread 将不影響由 GetThreadStatus 傳回的狀态。通過 JVMPI 挂起的線程的狀态将保持不變,并傳回挂起時的狀态。 

參數: 

env  - 線程的 JNIEnv *  

傳回值: 

JVMPI_THREAD_RUNNABLE  - 線程是可運作的。  
JVMPI_THREAD_MONITOR_WAIT  -線程在等待監控器。  
JVMPI_THREAD_CONDVAR_WAIT  - 線程在等待條件變量。  

當線程挂起(通過 java.lang.Thread.suspend)或處于以上中斷狀态時,将設定 JVMPI_THREAD_SUSPENDED 或 JVMPI_THREAD_INTERRUPTED 位。 


void (*NotifyEvent)(JVMPI_Event *event);
由虛拟機調用,用于将事件發送給監視程式代理。監視程式代理通過調用 EnableEvent 注冊它感興趣的事件類型,或通過調用 RequestEvent 請求特定的事件類型。 
當 EnableEvent 啟用事件時,産生該事件的線程就是發送該事件的線程。當 RequestEvent 請求事件時,請求事件的線程是發送該事件的線程。多個線程可以同時發送多個事件。 

如果事件特定資訊含有 jobjectID,則可在禁用 GC 的情況下調用該函數。函數傳回後将啟用 GC。 

配置設定給 JVMPI_Event 結構的空間和任何事件特定資訊在函數傳回時将由虛拟機釋放。監視程式代理必須複制任何需要保留在其内部緩沖區中的必要資料。 

參數: 

event  - 從虛拟機發送到監視程式代理的 JVMPI 事件。  


void (*ProfilerExit)(jint err_code);
由監視程式代理調用,用于通知虛拟機:監視程式想要退出并将錯誤代碼設定為 err_code。該函數将導緻虛拟機也以相同的 err_code 退出。 
參數: 

err_code  - 退出代碼  


JVMPI_RawMonitor (*RawMonitorCreate)(char *lock_name);
由監視程式調用,用于建立原監控器。 
原監控器類似于 Java 監控器,差别在于原監控器不與 Java 對象發生關聯關系。 

對于監視程式代理,線上程挂起模式中調用該函數是不安全的,因為該函數可以調用任意的系統函數(例如 malloc)和内部系統庫鎖定中的子產品。 

如果原監控器名字是用下劃線(“_”)開頭的,則其監控器競争事件不會發送給監視程式代理。 

參數: 

lock_name  - 原監控器名。  

傳回值: 

原監控器  


void (*RawMonitorDestroy)(JVMPI_RawMonitor lock_id);
由監視程式代理調用,用于銷毀原監控器并釋放所有與監控器相關聯的系統資源。 
原監控器與 Java 監控器類似,差别在于原監控器不與 Java 對象發生關聯關系。 

對于監視程式代理,線上程挂起模式中調用該函數是不安全的,因為該函數可以調用任意的系統函數(例如 free)和内部系統庫鎖定中的子產品。 

參數: 

lock_id  - 要銷毀的原監控器  


void (*RawMonitorEnter)(JVMPI_RawMonitor lock_id);
由監視程式代理調用,用于進入原監控器。 
原監控器與 Java 監控器類似,差别在于原監控器不與 Java 對象發生關聯關系。 

對于監視程式代理,線上程挂起模式中調用該函數是不安全的,因為目前的線程可能阻塞已挂起線程獲得的原監控器。 

參數: 

lock_id  - 要進入的原監控器  


void (*RawMonitorExit)(JVMPI_RawMonitor lock_id);
由監視程式代理調用,用于退出原監控器。 
原監控器與 Java 監控器類似,差别在于原監控器不與 Java 對象發生關聯關系。 

參數: 

lock_id  - 要退出的原監控器  


void (*RawMonitorNotifyAll)(JVMPI_RawMonitor lock_id);
由監視程式調用,用于通知所有等待原監控器的線程。 
原監控器與 Java 監控器類似,差别在于原監控器不與 Java 對象發生關聯關系。 

參數: 

lock_id  - 要通知的原監控器  


void (*RawMonitorWait)(JVMPI_RawMonitor lock_id, jlong ms);
由監視程式代理調用,用于等待原監控器指定逾時時間。将 0 作為逾時時間傳遞會導緻線程永久等待。 
原監控器與 Java 監控器類似,差别在于原監控器不與 Java 對象發生關聯關系。 

參數: 

lock_id  - 要等待的原監控器  
ms  - 等待時間(以毫秒計)。  


jint (*RequestEvent)(jint event_type, void *arg);
由監視程式代理調用,用于請求特定類型的通知事件。與 event_type 不同,監視程式代理也可傳遞參數,後者可提供給定事件類型的特定附加資訊。 
可以調用該函數來請求一次事件,例如 JVMPI_EVENT_HEAP_DUMP、JVMPI_EVENT_MONITOR_DUMP 和JVMPI_EVENT_OBJECT_DUMP。 這些事件的通知無法用 EnableEvent 和 DisableEvent 函數控制。 

另外,可以調用該函數來請求特定類、線程或對象的定義事件。當監視程式代理需要解決事件中所接收到的未知類、方法、線程或對象辨別符,而前面已禁用相應的定義事件時,它将非常有用。 

監視程式代理可通過請求 JVMPI_EVENT_CLASS_LOAD 事件并将事件特定參數設定為類對象辨別符,來接收有關未知類辨別符的資訊。 
監視程式代理可通過請求 JVMPI_EVENT_THREAD_START 事件并将事件特定參數設定成線程對象辨別符,來接受有關未知線程辨別符的資訊。 
監視程式代理可通過請求 JVMPI_EVENT_OBJECT_ALLOC 事件并将事件特定參數設定成對象辨別符,來接受有關未知對象辨別符的資訊,。 
是以,監視程式可通過調用 EnableEvent 異步啟用上述三種事件,也可通過調用 RequestEvent 同步請求這些事件。所請求的事件将在 RequestEvent 函數傳回之前從釋出 RequestEvent 調用的線程中發送。 

RequestEvent 函數不能用來請求其它沒有列出的事件。 

通過 RequestEvent 請求的事件在到達時将設定其 event_type 中的 JVMPI_REQUESTED_EVENT 位。 

參數: 

event_type  - 事件類型,JVMPI_EVENT_CLASS_LOAD 等。  
arg  - 事件特定參數。  

傳回值: 

JVMPI_SUCCESS  請求成功。  
JVMPI_FAIL  請求失敗。  
JVMPI_NOT_AVAILABLE  不能發出所請求的 event_type。  


void (*ResumeThread)(JNIEnv *env);
由監視程式代理調用,用于恢複線程。 
注意:由 java.lang.Thread.suspend 方法挂起的線程将不能用 JVMPI ResumeThread 函數恢複。 

參數: 

env  - 線程 JNIEnv *。  


void (*RunGC)(void);
由監視程式調用,用于強制完成垃圾收集。不能在禁用 GC 時調用該函數。 

void (*SetThreadLocalStorage)(JNIEnv *env_id, void *ptr);
由監視程式代理調用,用于設定 JVMPI 局部線程存儲空間的值。JVMPI 為代理提供指針大小的局部線程存儲空間,可用來記錄每個線程的監視程式資訊。 
參數: 

env_id  - 線程 JNIEnv *。  
ptr  - 要輸入局部線程存儲空間中的值。  


void (*SuspendThread)(JNIEnv *env);
由監視程式代理調用,用于挂起線程。系統在調用該函數後将進入線程挂起模式。 
注意:由 JVMPI SuspendThread 函數挂起的線程将不能用 java.lang.Thread.resume 方法恢複。 

在 JDK 1.2 的實作中,在禁用 GC 時必須調用該函數。所有線程均恢複前,GC 将保持無效。 

參數; 

env  - 線程 JNIEnv *。  


jboolean (*ThreadHasRun)(JNIEnv *env);
由監視程式代理調用,用于決定給定的 JNIEnv 指針辨別自從線程被 SuspendThread 挂起後是否消耗了 CPU 時間。當線程由 ResumeThread 恢複并接着由 SuspendThread 函數挂起時,必須調用該函數。 
參數: 

env  - 線程 JNIEnv *。  

傳回值: 

JNI_TRUE  - 線程獲得機會運作。  
JNI_FALSE  - 線程沒有獲得機會運作。  


3. 事件

JVMPI_EVENT_ARENA_DELETE
删除堆塊時發送。 
駐留在該塊中的所有對象均将被釋放,但并未為這些對象發送顯式的 JVMPI_EVENT_OBJECT_FREE。監視程式代理能通過跟蹤該塊中的對象配置設定和所有進出該塊中的對象來推斷目前滞留在該塊中的所有對象。 

該事件線上程挂起模式中釋出。監視程式不能做任何塊調用,包括進入監控器或從 C 堆中配置設定(例如通過 malloc)。 

該事件總是在 JVMPI_EVENT_GC_START 和 JVMPI_EVENT_GC_FINISH 事件之間發送。監視程式代理應獲得在 JVMPI_EVENT_GC_START 的事件處理程式中處理該事件所需的全部鎖定。 

struct {
    jint arena_id;
} delete_arena;


内容: 

arena_id  - 删除塊的辨別符。  


JVMPI_EVENT_ARENA_NEW
為配置設定對象建立新塊時發送。 
struct {
    jint arena_id;
    char *arena_name;
} new_arena;


内容: 

arena_id  - 給定塊的辨別符。  
arena_name  - 塊名。  


JVMPI_EVENT_CLASS_LOAD
當在虛拟機中加載類或當監視程式代理通過釋出 RequestEvent 調用請求 JVMPI_EVENT_CLASS_LOAD 事件時發送。對于後一種情況,将設定事件類型中的 JVMPI_REQUESTED_EVENT 位。 
該事件可在禁用 GC 的情況下發出。NotifyEvent   GC。 

struct {
    char *class_name;
    char *source_name;
    jint num_interfaces;
    jint num_methods;
    JVMPI_Method *methods;
    jint num_static_fields;
    JVMPI_Field *statics;
    jint num_instance_fields;
    JVMPI_Field *instances;
    jobjectID class_id;
} class_load;

内容: 

class_name  - 要加載的類名。  
source_name  - 定義類的源檔案名。  
num_interfaces  - 該類實作的接口數。  
方法  - 該類中定義的方法。  
num_static_fields  - 該類中定義的靜态域數。  
靜态域  - 該類中定義的靜态域。  
num_instance_fields  - 該類中定義的執行個體域數。  
執行個體  - 該類中定義的執行個體域。  
class_id  - 類對象辨別符。  

注意:類辨別符是類對象的辨別符,并将在 JVMPI_EVENT_OBJECT_MOVE 發生時改變。 


JVMPI_EVENT_CLASS_LOAD_HOOK
當虛拟機獲得類檔案資料,但同時又尚未構造該類的記憶體表示前發送。監視程式代理可讓虛拟機發送的現有類檔案資料中包括監視程式鈎子。 
監視程式必須使用在該事件中發送的記憶體配置設定函數指針為更改的類檔案資料緩沖區配置設定空間,因為虛拟機負責着釋放新類檔案的資料緩沖區。 

struct {
    unsigned char *class_data;
    jint class_data_len;
    unsigned char *new_class_data;
    jint new_class_data_len;
    void * (*malloc_f)(unsigned int);
} class_load_hook;

内容: 

class_data  - 目前類檔案資料緩沖區指針。  
class_data_len  - 目前類檔案資料緩沖區長度。  
new_class_data  - 配置的類檔案資料緩沖區指針。  
new_class_data_len  - 新類檔案資料緩沖區長度。  
malloc_f  - 記憶體配置設定函數指針。  

監視程式代理在從 NotifyEvent 傳回前必須将 new_class_data 設定成指向配置的類檔案資料緩沖區,并将 new_class_data_len 設定為該緩沖區的長度。如果選擇不配置該類,則必須将 new_class_data 和 new_class_data_len 設定成原來的值。 


JVMPI_EVENT_CLASS_UNLOAD
類解除安裝時發送。 
該事件可在禁用 GC 的情況下發出。NotifyEvent  GC。 

struct {
    jobjectID class_id;
} class_unload;

内容: 

class_id  - 要解除安裝的類。  


JVMPI_EVENT_COMPILED_METHOD_LOAD
當編譯完方法并将其加載到記憶體中時發送。 
struct {
    jmethodID method_id;
    void *code_addr;
    jint code_size;
    jint lineno_table_size;
    JVMPI_Lineno *lineno_table;
} compiled_method_load;

内容: 

method_id  - 要編譯和加載的方法。  
code_addr  - 編譯方法代碼加載位址。  
code_size  - 編譯代碼大小。  
lineno_table_size  - 行号表大小。  
lineno_table  - 從方法開始到源檔案行号的表映射偏移量。  


JVMPI_EVENT_COMPILED_METHOD_UNLOAD
當編譯完的方法從記憶體中解除安裝時發送。 
struct {
    jmethodID method_id;
} compiled_method_unload;

内容: 

method_id  - 要解除安裝的編譯方法。  


JVMPI_EVENT_DATA_DUMP_REQUEST
由虛拟機發送,用于請求監視程式代理轉儲其資料。這僅是一種暗示且監視程式代理無需響應該事件。它對于來自使用者的指令行信号處理非常有用。例如在 JDK 1.2 中,Win32 中的 CTRL-Break 和 Solaris 中的 CTRL-\ 即幫助虛拟機将該事件發送給監視程式代理。 
沒有事件特定的資訊。 


JVMPI_EVENT_DATA_RESET_REQUEST
由虛拟機發送,用于請求監視程式代理重新設定其資料。這僅是一種暗示且監視程式代理無需響應該事件。它對于來自使用者的指令行信号處理非常有用。例如在 JDK 1.2 中,Win32 中的 CTRL-Break 和 Solaris 中的 CTRL-\ 即幫助虛拟機将該事件發送給監視程式代理。 
沒有事件特定的資訊。 


JVMPI_EVENT_GC_FINISH
當 GC 完成時發送。監視程式代理可釋放任何鎖定,包括 GC 處理對象釋放、對象移動和塊删除事件時啟動通知期間所擷取的鎖定。系統在該事件後将傳回多線程模式。 
事件特定的資料包含 Java 堆的統計資料。 

struct {
    jlong used_objects;
    jlong used_object_space;
    jlong total_object_space;
} gc_info;


内容: 

used_objects  - 堆中使用的對象數。  
used_object_space  - 對象使用的空間數(以位元組計)。  
total_object_space  - 對象空間總數(以位元組計)。  


JVMPI_EVENT_GC_START
在 GC 将要啟動時發送。系統在該事件後将進入線程挂起模式。為避免死鎖,監視程式代理應該擷取在該事件的事件處理程式中處理對象釋放、對象移動和塊删除事件所需的任何鎖定。 
沒有事件特定的資訊。 


JVMPI_EVENT_HEAP_DUMP
當接受 RequestEvent 函數請求時發送。監視程式代理可通過将 JVMPI_HeapDumpArg 結構作為第二個參數傳給 RequestEvent,同時将 heap_dump_level 域設為想要的轉儲級别來指定所要轉儲資訊的級别。 
轉儲級别值可以為: 

JVMPI_DUMP_LEVEL_0 
JVMPI_DUMP_LEVEL_1 
JVMPI_DUMP_LEVEL_2 
如果傳遞 NULL 值,則轉儲級别将設定為 JVMPI_DUMP_LEVEL_2。 

該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

事件特定的資料中包含 Java 堆中所有活動對象的快照。 

struct {
    int dump_level;
    char *begin;
    char *end;
    jint num_traces;
    JVMPI_CallTrace *traces;
} heap_dump;

内容: 

dump_level  - 在 RequestEvent 中指定的轉儲級别  
begin  - 堆轉儲開始  
end  - 堆轉儲結束  
num_traces  - GC 根所駐留的棧跟蹤數,0 表示 JVMPI_DUMP_LEVEL_0  
跟蹤  - GC 根所駐留的棧跟蹤  

begin 和 end 之間的堆轉儲格式取決于請求的資訊級别,其格式将在 JVMPI 轉儲格式一節中詳細介紹。 


JVMPI_EVENT_JNI_GLOBALREF_ALLOC
建立 JNI 全局引用時發送。事件特定的資料包含 JNI 全局引用和相應的對象辨別符。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jobjectID obj_id;
    jobject ref_id;
} jni_globalref_alloc;

内容: 

obj_id  - 全局引用所引用的對象辨別符。  
ref_id  - JNI 全局引用。  


JVMPI_EVENT_JNI_GLOBALREF_FREE
删除 JNI 全局引用時發送。事件特定的資料包含要删除的 JNI 全局引用。 
struct {
    jobject ref_id;
} jni_globalref_free;

内容: 

ref_id  - JNI 全局引用。  


JVMPI_EVENT_JNI_WEAK_GLOBALREF_ALLOC
建立 JNI 弱全局引用時發送。事件特定的資料包含 JNI 弱全局引用和相應的對象辨別符。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jobjectID obj_id;
    jobject ref_id;
} jni_globalref_alloc;

内容: 

obj_id  - 弱全局引用所引用的對象辨別符。  
ref_id  - JNI 弱全局引用。  


JVMPI_EVENT_JNI_WEAK_GLOBALREF_FREE
删除 JNI 弱全局引用時發送。事件特定的資料包含要删除的 JNI 弱全局引用。 
struct {
    jobject ref_id;
} jni_globalref_free;

内容: 

ref_id  - JNI 弱全局引用。  


JVMPI_EVENT_JVM_INIT_DONE
初始化完成時由虛拟機發送。僅當通知該事件之後調用 CreateSystemThread 才是安全的。 
無事件特定的資料。 


JVMPI_EVENT_JVM_SHUT_DOWN
當虛拟機關閉時由改虛拟機發送。監視程式通常将儲存監視程式資料。 
無事件特定的資料。 


JVMPI_EVENT_METHOD_ENTRY
當進入方法時發送。與 JVMPI_EVENT_METHOD_ENTRY2 相比,該事件不發送調用其方法的目标對象的 jobjectID。 
struct {
    jmethodID method_id;
} method;

内容: 

method_id  - 要進入的方法。  


JVMPI_EVENT_METHOD_ENTRY2
當進入方法時發送。如果方法是執行個體方法,則目标對象的 jobjectID 與該事件一起發送。如果方法是靜态方法,則該事件中的 obj_id 域将被設定為 NULL。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jmethodID method_id;
    jobjectID obj_id;
} method_entry2;

内容: 

method_id  - 要進入的方法。  
obj_id  - 目标對象,靜态方法為 NULL。  


JVMPI_EVENT_METHOD_EXIT
當退出方法時發送。方法退出可以是正常退出,也可以是由未處理異常引起的退出。 
struct {
    jmethodID method_id;
} method;

内容: 

method_id  - 要進入的方法。  


JVMPI_EVENT_MONITOR_CONTENDED_ENTER
當線程試圖進入已經由另一線程獲得的 Java 監控器時發送。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jobjectID object;
} monitor;

内容: 

object  - 與監控器相關聯的對象辨別符  


JVMPI_EVENT_MONITOR_CONTENDED_ENTERED
當線程在等待被另一線程釋放後進入 Java 監控器時發送。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jobjectID object;
} monitor;

内容: 

object  - 與監控器相關聯的對象辨別符  


JVMPI_EVENT_MONITOR_CONTENDED_EXIT
當線程退出 Java 監控器,同時另一線程正等待獲得相同監控器時發送。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jobjectID object;
} monitor;

内容: 

object  - 與監控器相關聯的對象辨別符  


JVMPI_EVENT_MONITOR_DUMP
當由 RequestEvent 函數請求時發送。 
事件特定的資料包含虛拟機中所有線程和監控器的快照。 

該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    char *begin;
    char *end;
    jint num_traces;
    JVMPI_CallTrace *traces;
    jint *threads_status;
} monitor_dump;

内容: 

begin  - 監控器轉儲緩沖區開始。  
end  - 轉儲緩沖區結束  
num_traces  - 線程跟蹤數。  
traces  - 所有線程的跟蹤。  
thread_status  - 所有線程的狀态。  

監控器轉儲緩沖區格式将在 JVMPI 轉儲格式一節中詳細介紹。 


JVMPI_EVENT_MONITOR_WAIT
當線程要等待對象時發送。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jobjectID object;
    jlong timeout;
} monitor_wait;

内容: 

object  - 目前線程等待的對象辨別符。  
 (NULL 訓示線程處于 Thread.sleep)  
timeout  - 線程等待的毫秒數(0 表示永久等待)。  


JVMPI_EVENT_MONITOR_WAITED
當線程完成等待對象時發送。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jobjectID object;
    jlong timeout;
} monitor_wait;

内容: 

object  - 目前線程等待的對象辨別符。  
 (NULL 訓示線程處于 Thread.sleep中)  
timeout  - 線程等待的毫秒數。  


JVMPI_EVENT_OBJECT_ALLOC
當配置設定對象或當監視程式通過發出 RequestEvent 調用請求 JVMPI_EVENT_OBJECT_ALLOC 事件時發送。對于後一種情況,将設定事件類型中的 JVMPI_REQUESTED_EVENT 位。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    jint arena_id;
    jobjectID class_id;
    jint is_array;
    jint size;
    jobjectID obj_id;
} obj_alloc;

内容: 

arena_id  - 配置設定的塊。  
class_id  - 該對象所屬的類,當 is_array 是 JVMPI_CLASS 時為數組元素類。  
is_array  - 其值可以為:  
 JVMPI_NORMAL_OBJECT 正常對象  
JVMPI_CLASS 對象數組  
JVMPI_BOOLEAN 布爾數組  
JVMPI_BYTE 位元組數組  
JVMPI_CHAR 字元數組  
JVMPI_SHORT 短整數數組  
JVMPI_INT 整數數組  
JVMPI_LONG 長整數數組  
JVMPI_FLOAT 浮點型數組  
JVMPI_DOUBLE 雙精度型數組  
 
size  - 位元組數。  
obj_id  - 唯一的對象辨別符。  


JVMPI_EVENT_OBJECT_DUMP
當 RequestEvent 函數請求時發送。請求轉儲對象的 jobjectID 應作為第二參數傳遞給 RequestEvent。 
監視程式代理應在禁用 GC 後再請求該事件。 

事件特定的資料包含對象的快照。 

struct {
    jint data_len;
    char *data;
} object_dump;

内容: 

data_len  - 對象轉儲緩沖區的長度  
data  - 對象轉儲開始  

對象轉儲緩沖區的格式将在 JVMPI 轉儲格式一節中詳細介紹。 


JVMPI_EVENT_OBJECT_FREE
當釋放對象時發送。 
該事件将以線程挂起模式發出。監視程式不能執行任何塊調用,包括進入監控器或從 C 堆中配置設定塊(例如通過 malloc)。 

該事件總是在 JVMPI_EVENT_GC_START 和 JVMPI_EVENT_GC_FINISH 事件之間發送。監視程式代理應獲得在 JVMPI_EVENT_GC_START 的事件處理程式中處理該事件所需要的全部鎖定。 

struct {
    jobjectID obj_id;
} obj_free;

内容: 

obj_id  - 要釋放的對象。  


JVMPI_EVENT_OBJECT_MOVE
當對象移到堆中時發送。 
該事件将以線程挂起模式發出。監視程式不能執行何塊調用,包括進入監控器或從 C 堆中配置設定塊(例如通過 malloc)。 

該事件總是在 JVMPI_EVENT_GC_START 和 JVMPI_EVENT_GC_FINISH 事件間發送。監視程式代理應獲得在 JVMPI_EVENT_GC_START 的事件處理程式中處理該事件所需的全部鎖定。 

 struct {
     jint arena_id;
     jobjectID obj_id;
     jint new_arena_id;
     jobjectID new_obj_id;
} obj_move;

内容: 

arena_id  - 目前塊。  
obj_id  - 目前對象辨別符。  
new_arena_id  - 新塊。  
new_obj_id  - 新對象辨別符。  


JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTER
當線程試圖進入已被另一線程獲得的原監控器時發送。 
struct {
    char *name;
    JVMPI_RawMonitor id;
} raw_monitor;

内容: 

name  - 原監控器名  
id  - 原監控器辨別符  


JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTERED
當線程在等待被另一線程釋放後進入原監控器時發送。 
struct {
    char *name;
    JVMPI_RawMonitor id;
} raw_monitor;

内容: 

name  - 原監控器名  
id  - 原監控器辨別符  


JVMPI_EVENT_RAW_MONITOR_CONTENDED_EXIT
當線程退出原監控器且另一線程在等待獲得相同的監控器時發送。 
struct {
    char *name;
    JVMPI_RawMonitor id;
} raw_monitor;

内容: 

name  - 原監控器名  
id  - 原監控器辨別符  


JVMPI_EVENT_THREAD_END
當線程在虛拟機中結束時發送。 
該事件通知中所接收的 JVMPI_Event 的 env_id 域是要結束線程的 JNIEnv 接口指針。 


JVMPI_EVENT_THREAD_START
當線程在虛拟機中啟動,或當監視程式代理通過發出 RequestEvent 調用請求 JVMPI_EVENT_THREAD_START 事件時發送。對于後一種情況,将設定事件類型中的 JVMPI_REQUESTED_EVENT 位。 
該事件可在禁用 GC 的情況下發出。NotifyEvent 傳回後将重新啟用 GC。 

struct {
    char *thread_name;
    char *group_name;
    char *parent_name;
    jobjectID thread_id;
    JNIEnv *thread_env_id;
} thread_start;

内容: 

thread_name  - 要啟動的線程名。  
group_name  - 線程所屬的組。  
parent_name  - 父線程名。  
thread_id  - 線程對象辨別符。  
thread_env_id  - 線程的 JNIEnv *。  

線程與 JNIEnv 指針和線程對象辨別符相關聯。JVMPI 使用 JNIEnv 指針作為線程辨別符。 


4. 轉儲格式

4.1 轉儲格式描述中使用的大小和類型
u1: 1 位元組  
u2: 2 位元組  
u4: 4 位元組  
u8: 8 位元組  
ty: u1 其中: 
 JVMPI_NORMAL_OBJECT牋 普通對象  
JVMPI_CLASS 對象數組  
JVMPI_BOOLEAN 布爾數組  
JVMPI_BYTE 位元組數組  
JVMPI_CHAR 字元數組  
JVMPI_SHORT 短整數數組  
JVMPI_INT 整數數組  
JVMPI_LONG 長整數數組  
JVMPI_FLOAT 浮點型數組  
JVMPI_DOUBLE 雙精度型數組  
 
vl: 值,精确大小依賴于值的類型: 
 boolean, byte  u1  
short, char  u2  
int, float  u4  
long, double  u8  
JNIEnv *, jobjectID 和 JVMPI_RawMonitor牋 sizeof(void *) 
 


4.2 堆轉儲格式
堆轉儲格式取決于所請求資訊的級别。 

JVMPI_DUMP_LEVEL_0:
轉儲由下列格式的記錄序列組成: 

ty  對象類型  
jobjectID  對象  

JVMPI_DUMP_LEVEL_1:
轉儲格式與 JVMPI_DUMP_LEVEL_2 基本相同,但轉儲中不包括下列值:對象執行個體轉儲中的基本域、類轉儲中的基本靜态域和基本數組元素。 

JVMPI_DUMP_LEVEL_2:
轉儲由記錄序列組成,其中每條記錄包括一個 8 位記錄類型,後跟其格式與記錄類型相應的資料。 

記錄類型  記錄資料  
JVMPI_GC_ROOT_UNKNOWN 
(未知根)  jobjectID  對象  
 
JVMPI_GC_ROOT_JNI_GLOBAL 
(JNI 全局引用根)  jobjectID  對象  
jobject  JNI 全局引用  
 
JVMPI_GC_ROOT_JNI_LOCAL 
(JNI 局部引用)  jobjectID  對象  
JNIEnv *  線程  
u4  棧跟蹤中的架構号(-1 代表空)  
 
JVMPI_GC_ROOT_JAVA_FRAME 
(Java 棧架構)  jobjectID  對象  
JNIEnv *  線程  
u4  棧跟蹤中的架構号(-1 代表空)  
 
JVMPI_GC_ROOT_NATIVE_STACK 
(本地棧)  jobjectID  對象  
JNIEnv *  線程  
 
JVMPI_GC_ROOT_STICKY_CLASS 
(系統類)  jobjectID  類對象  
 
JVMPI_GC_ROOT_THREAD_BLOCK 
(線程塊中的引用)  jobjectID  線程對象  
JNIEnv *  線程  
 
JVMPI_GC_ROOT_MONITOR_USED 
(進入的監控器)  jobjectID  對象  
 
JVMPI_GC_CLASS_DUMP 
(類對象轉儲)  jobjectID  類  
jobjectID  超類  
jobjectID  類加載器  
jobjectID  簽名人  
jobjectID  保護域  
void *  保留  
void *  保留  
u4  執行個體大小(以位元組計)  
[jobjectID]*  接口  
u2  常量緩沖池大小  
[u2,  常量緩沖池索引,  
爐y,  類型,  
爒l]*  值  
[vl]*  靜态域值  
 
JVMPI_GC_INSTANCE_DUMP 
(正常對象轉儲)  jobjectID 對象  
jobjectID 類  
u4  後面的位元組數  
[vl]*  執行個體域值(類,後跟超類,超類的超類 ...)  
 
JVMPI_GC_OBJ_ARRAY_DUMP 
(對象數組轉儲)  jobjectID  數組對象  
u4  元素數  
jobjectID  元素類辨別符(在 JDK 1.2 版中可以是 NULL。)  
[jobjectID]*  元素  
 
JVMPI_GC_PRIM_ARRAY_DUMP 
(基本數組轉儲)  jobjectID  數組對象  
u4  元素數  
ty  元素類型  
[vl]*  元素  
 


4.3 對象轉儲格式
轉儲緩沖區由單條記錄組成,其中包括一個 8 位記錄類型,後跟相應于該記錄類型格式的資料。記錄類型可以是: 

JVMPI_GC_CLASS_DUMP 
JVMPI_GC_INSTANCE_DUMP 
JVMPI_GC_OBJ_ARRAY_DUMP 
JVMPI_GC_PRIM_ARRAY_DUMP 
每個記錄類型的資料格式與以前在堆轉儲格式章節中所述的相同。資訊級别與 JVMPI_DUMP_LEVEL_2 相同,包括下面所有值:對象執行個體轉儲中的基本域、類轉儲中的基本靜态域和基本數組元素。 

4.4 監控器轉儲格式
轉儲緩沖區由記錄序列組成,其中每個記錄包括一個 8 位記錄類型,後跟相應記錄類型的資料。 

記錄類型  記錄資料  
JVMPI_MONITOR_JAVA 
(Java 監控器)  jobjectID  對象辨別符  
JNIEnv *  業主線程  
u4  項計數  
u4  等待進入的線程數  
[JNIEnv *]*  等待進入的線程  
u4  等待通知的線程數  
[JNIEnv *]*  等待通知的線程  
 
JVMPI_MONITOR_RAW 
(原監控器)  char *  原監控器名  
JVMPI_RawMonitor  原監控器辨別符  
JNIEnv *  業主線程  
u4  項計數  
u4  等待進入的線程數  
[JNIEnv *]*  等待進入的線程  
u4  等待通知的線程數  
[JNIEnv *]*  等待通知的線程  
 


5. 資料類型
字元使用 Java 虛拟機規範中的 UTF-8 編碼方式進行編碼。 

jobjectID
代表對象辨別符的不透明指針。 
struct _jobjectID;
typedef struct _jobjectID * jobjectID;


JVMPI_CallFrame
要執行的方法。 
typedef struct {
    jint lineno;
    jmethodID method_id;
} JVMPI_CallFrame;

域: 

行号  - 源檔案裡的行号。  
method_id  - 要執行的方法。  


JVMPI_CallTrace
方法所執行的調用跟蹤。 
typedef struct {
    JNIEnv *env_id;
    jint num_frames;
    JVMPI_CallFrame *frames;
} JVMPI_CallTrace;

域: 

env_id  - 執行該跟蹤的線程辨別符。  
num_frames  - 跟蹤中的架構數。  
架構  - 組成該跟蹤的 JVMPI_CallFrame。調用程式位于被調用程式之後。  


JVMPI_Field
類中定義的域。 
typedef struct {
    char *field_name;
    char *field_signature;
} JVMPI_Field;

域: 

field_name  - 域名  
field_signature  - 域簽名  


JVMPI_HeapDumpArg
請求堆轉儲的附加資訊。 
typedef struct {
    jint heap_dump_level;
} JVMPI_HeapDumpArg;

域: 

heap_dump_level  - 堆轉儲資訊級别,值可以為:  
 JVMPI_DUMP_LEVEL_0  
JVMPI_DUMP_LEVEL_1  
JVMPI_DUMP_LEVEL_2  
 


JVMPI_Lineno
源行号與相對已編譯方法開始位置的偏移量之間的映射。 
typedef struct {
    jint offset;
    jint lineno;
} JVMPI_Lineno;

域: 

offset  - 距離方法開始位置的偏移量  
lineno  - 源檔案開始位置的行号  


JVMPI_Method
類中定義的方法。 
typedef struct {
    char *method_name;
    char *method_signature;
    jint start_lineno;
    jint end_lineno;
    jmethodID method_id;
} JVMPI_Method;

域 

method_name  - 方法名  
method_signature  - 方法簽名  
start_lineno  - 源檔案中的起始行号  
end_lineno  - 源檔案中的結束行号  
method_id  - 賦予該方法的辨別符  


JVMPI_RawMonitor
代表原監控器的不透明指針。 
struct _JVMPI_RawMonitor;
typedef struct _JVMPI_RawMonitor * JVMPI_RawMonitor;


6. JDK 1.2 實作局限性的說明
對象數組的 JVMPI_EVENT_OBJECT_ALLOC 事件釋出時的元素類辨別符未知(例如 class_id 域總是 NULL)。 
在 Win32 中,JIT 編譯器還不支援下列事件: 
JVMPI_EVENT_METHOD_ENTRY、 
JVMPI_EVENT_METHOD_ENTRY2、 
JVMPI_EVENT_METHOD_EXIT、 
JVMPI_EVENT_COMPILED_METHOD_LOAD 和 
JVMPI_EVENT_COMPILED_METHOD_UNLOAD。 
必須在禁用 GC 後再調用 SuspendThread。在所有線程恢複前,GC 必須保持禁用狀态。 
主線程(虛拟機建立的第一個線程)的線程啟動事件可在其他引用 JNIEnv 接口指針的事件之後到達。 
永遠不要釋出 JVMPI_EVENT_ARENA_NEW 和 JVMPI_EVENT_ARENA_DELETE 事件。其它事件中的塊辨別符應始終設定為 1。 
--------------------------------------------------------------------------------

上次更新時間:1998 年 11 月 11 日,星期三,14:14:44 PST