Õ¾ÄÚËÑË÷: ÇëÊäÈëËÑË÷¹Ø¼ü´Ê

µ±Ç°Ò³Ãæ: ¿ª·¢×ÊÁÏÊ×Ò³ ¡ú Java רÌâ ¡ú ÓÃJVM¹¤¾ß½Ó¿Ú´´½¨µ÷ÊԺͷÖÎö´úÀí

ÓÃJVM¹¤¾ß½Ó¿Ú´´½¨µ÷ÊԺͷÖÎö´úÀí

ÕªÒª: Java ÐéÄâ»ú¹¤¾ß½Ó¿ÚÌṩÁËÒ»ÖÖ±à³Ì½Ó¿Ú£¬ÔÊÐíÈí¼þ¿ª·¢ÈËÔ±´´½¨Èí¼þ´úÀíÒÔ¼àÊӺͿØÖÆ Java ±à³ÌÓïÑÔÓ¦ÓóÌÐò
¡¡¡¡Java ÐéÄâ»ú¹¤¾ß½Ó¿Ú£¨Java Virtual Machine Tool Interface£¬JVMTI£©ÌṩÁËÒ»ÖÖ±à³Ì½Ó¿Ú£¬ÔÊÐíÈí¼þ¿ª·¢ÈËÔ±´´½¨Èí¼þ´úÀíÒÔ¼àÊӺͿØÖÆ Java ±à³ÌÓïÑÔÓ¦ÓóÌÐò¡£JVMTI ÊÇ Java 2 Software Development Kit (SDK), Standard Edition, °æ±¾ 1.5.0 ÖеÄÒ»ÖÖÐÂÔö¹¦ÄÜ¡£ËüÈ¡´úÁË Java Virtual Machine Profiling Interface (JVMPI)£¬´Ó°æ±¾ 1.1 Æð¼´×÷Ϊ Java 2 SDK µÄÒ»ÖÖʵÑ鹦ÄÜ°üÀ¨ÔÚÄÚ¡£ÔÚ JSR-163 ÖÐ¶Ô JVMTI ½øÐÐÁËÓйØ˵Ã÷¡£

¡¡¡¡±¾ÎIJûÊöÈçºÎʹÓà JVMTI ´´½¨ Java Ó¦ÓóÌÐòµÄµ÷ÊԺͷÖÎö¹¤¾ß¡£ÕâÖÖ¹¤¾ß£¨Ò²³Æ×÷´úÀí£©ÔÚÓ¦ÓóÌÐòÖз¢Éúʼþʱ£¬Äܹ»Ê¹ÓøýӿÚÌṩµÄ¹¦ÄܶÔʼþ֪ͨ½øÐÐ×¢²á£¬²¢²éѯºÍ¿ØÖƸÃÓ¦ÓóÌÐò¡£ÕâÀïÌṩÁË JVMTI µÄÎĵµ×ÊÁÏ¡£JVMTI ´úÀí¶ÔÓÚµ÷ÊԺ͵÷ÓÅÓ¦ÓóÌÐòÊ®·ÖÓÐÓá£Ëü¿ÉÒÔ¶ÔÓ¦ÓóÌÐòµÄ¸÷¸ö·½ÃæÓèÒÔ˵Ã÷£¬ÈçÄÚ´æ·ÖÅäÇé¿ö¡¢CPU ÀûÓÃÇé¿ö¼°ËøÕù¶áÇé¿ö¡£

¡¡¡¡¾¡¹Ü JVMPI ÏÖÔÚÈÔ´¦ÓÚʵÑé½×¶Î£¬ºÜ¶à Java ¼¼Êõ¿ª·¢ÈËÔ±ÒѾ­ÔÚʹÓÃËüÁË£¬¶øÇÒÒѾ­°ÑËüÓ¦Óõ½¶àÖÖÊг¡ÉÏÌṩµÄ Java Ó¦ÓóÌÐò Profiler¡£Çë×¢Ò⣬¼«Á¦¹ÄÀø¿ª·¢ÈËԱʹÓà JVMTI ¶ø²»Ê¹Óà JVMPI¡£JVMPI ÔÚ²»¾ÃµÄ½«À´½«±»·ÏÖ¹¡£

¡¡¡¡JVMTI ÔÚ¶à¸ö·½Ãæ¸Ä½øÁË JVMPI µÄ¹¦ÄܺÍÐÔÄÜ¡£ÀýÈ磺

¡¡¡¡1) JVMTI ÒÀÀµÓÚÿ¸öʼþµÄ»Øµ÷¡£Õâ±È JVMPI Éè¼ÆʹÓÃÐèÒª±à×éºÍÈ¡Ïû±à×éµÄʼþ½á¹¹¸üÓÐЧ¡£

¡¡¡¡2)¡¡JVMTI °üº¬Ëı¶ÓÚ JVMPI µÄº¯Êý£¨°üÀ¨ÓÃÓÚ»ñÈ¡¹ØÓÚ±äÁ¿¡¢×ֶΡ¢·½·¨ºÍÀàµÄÐÅÏ¢µÄ¸ü¶àº¯Êý£©¡£ÓÐ¹Ø JVMTI º¯ÊýµÄÍêÕûË÷Òý£¬Çë²Î¼ûº¯ÊýË÷ÒýÒ³¡£

¡¡¡¡3)¡¡JVMTI ±È JVMPI Ìṩ¸ü¶àÀàÐ͵Äʼþ֪ͨ£¬°üÀ¨Ò쳣ʼþ¡¢×ֶηÃÎʺÍÐÞ¸Äʼþ¡¢¶ÏµãºÍµ¥²½ÖèʼþµÈ¡£

¡¡¡¡ÓÐЩ´Óδ±»³ä·ÖÀûÓÃµÄ JVMPI ʼþ£¬Èç Arena µÄ new ºÍ delete£¬»òÕßͨ¹ý×Ö½ÚÂ빤¾ßºÜÈÝÒ×¾ÍÄÜ»ñµÃµÄÄÚÈÝ£¬»òÕß JVMTI º¯Êý±¾Éí£¨Èç heap dump ºÍ object allocation£©ÍùÍù±» ¶ªµô¡£ ¶ÔÕâЩʼþµÄÃèÊöλÓÚʼþË÷ÒýÒ³¡£

¡¡¡¡JVMTI ÊÇ»ùÓÚ¹¦Äܵģ¬¶ø JVMPI ¶ÔÓÚÏàÓ¦ÐÔÄÜÓ°ÏìÈ´ÊÇ¡°ÒªÃ´È«ÓУ¬ÒªÃ´È«ÎÞ¡±¡£

¡¡¡¡JVMPI ¶Ñ¹¦Äܲ»¿ÉÉìËõ¡£

¡¡¡¡JVMPI ûÓдíÎó·µ»ØÐÅÏ¢¡£

¡¡¡¡JVMPI ÔÚ VM ʵÏÖ·½Ãæ¾ßÓкÜÇ¿µÄÇÖÈëÐÔ£¬ÈÝÒ×µ¼ÖÂά»¤ÎÊÌâºÍÐÔÄÜÊÜËð¡£

¡¡¡¡JVMPI ÊǸöʵÑé²úÆ·£¬²»¾Ã½«·ÏÖ¹¡£

¡¡¡¡ÔÚ±¾ÎĵÄÒÔϲ¿·Ö£¬ÎÒÃǽéÉÜÒ»¸ö¼òµ¥´úÀí£¬ËüʹÓà JVMTI º¯Êý´Ó Java Ó¦ÓóÌÐòÌáÈ¡ÐÅÏ¢¡£ ´úÀíµÄ±àд±ØÐëʹÓñ¾µØ´úÂë¡£ÕâÀï¸ø³öµÄʾÀý´úÀíÊÇʹÓà C ÓïÑÔ±àдµÄ¡£Äú¿ÉÒÔÓÚ´ËÏÂÔØÍ êÕûµÄʾÀý´úÀí´úÂë¡£ÏÂÃ漸¶Î½éÉÜÈçºÎ³õʼ»¯Ò»¸ö´úÀí£¬ÒÔ¼°´úÀíÈçºÎʹÓà JVMTI º¯ÊýÌáÈ¡¹ØÓÚ Java Ó¦ÓóÌÐòµÄÐÅÏ¢£¬ÒÔ¼°ÈçºÎ±àÒëºÍÔËÐдúÀí¡£´ËʾÀý´úÂëºÍ±àÒë²½ÖèÌض¨ÓÚ UNIX »·¾³£¬µ«ÊǾ­¹ýÐ޸ĺóÒ²¿ÉÓÃÓÚ Windows¡£ÕâÀï½éÉܵĴúÀí¿ÉÓÃÓÚÔÚÈκΠJava Ó¦ÓóÌÐòÖзÖÎöÏ̺߳ÍÈ·¶¨ JVM ÄÚ´æʹÓÃÇé¿ö¡£

¡¡¡¡ÕâÀï°üº¬Ò»¸öÓà Java ÓïÑÔ±àдµÄ¼òµ¥³ÌÐò£¬³Æ×÷ SimpleThread.java£¬²¢¿É´ÓÕâÀïÏÂÔØ¡£ÎÒÃÇʹÓà ThreadSample.java ÑÝʾ´Ë´úÀíµÄÔ¤ÆÚÊä³ö¡£

¡¡¡¡JVMTI µÄ¹¦Äܺܶ࣬ÔÚ´ËÎÞ·¨ÏêÊö£»µ«±¾ÎÄÖеĴúÂë¿ÉÒÔÌṩһ¸ö³ö·¢µã£¬ÈÃÄúÈ¥¿ª·¢·ûºÏ×Ô¼ºÌض¨ÐèÇóµÄ·ÖÎö¹¤¾ß¡£

¡¡¡¡´úÀí³õʼ»¯

¡¡¡¡±¾½Ú½éÉÜÓÃÓÚ³õʼ»¯´úÀíµÄ´úÂë¡£Ê×ÏÈ£¬´úÀí±ØÐë°üÀ¨ jvmti.h Îļþ£¬Óï¾äΪ #include ¡£

¡¡¡¡ÁíÍ⣬´úÀí±ØÐë°üº¬Ò»¸öÃûΪ Agent_OnLoad µÄº¯Êý£¬¼ÓÔØ¿âʱҪµ÷ÓÃÕâÒ»º¯Êý¡£Agent_OnLoad º¯ÊýÓÃÓÚÔÚ³õʼ»¯ Java virtual machine (JVM) ֮ǰÉèÖÃËùÐèµÄ¹¦ÄÜ¡£Agent_OnLoad Ç©ÃûÈçÏÂËùʾ£º

<table borderColor=#ffcc66 width="90%" align=center bgColor=#c8c7b9 border=1> <tr> <td>JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
...

/* We return JNI_OK to signify success */
return JNI_OK;
}</td></tr></table>
¡¡¡¡ÔÚÎÒÃǵÄʾÀý´úÂëÖУ¬ÎÒÃDZØÐëΪ½«ÒªÊ¹ÓÃµÄ JVMTI º¯ÊýºÍʼþÆôÓöàÖÖ¹¦ÄÜ¡£Ò»°ãÇé¿öϾùÐ裨ÔÚijЩÇé¿öϱØÐ룩½«ÕâЩ¹¦ÄÜÌí¼Óµ½ Agent_OnLoad º¯ÊýÖС£ÓйØÿÖÖº¯Êý»òʼþËùÐèµÄ¹¦ÄܵÄ˵Ã÷£¬²Î¼û Java ÐéÄâ»ú¹¤¾ß½Ó¿ÚÒ³¡£ÀýÈ磬ҪʹÓà InterruptThread º¯Êý£¬can_signal_thread ¹¦ÄܱØÐëΪ true¡£ÎÒÃÇ°ÑʾÀýËùÐèµÄÈ«²¿¹¦Äܶ¼ÉèÖÃΪ true£¬È»ºóʹÓà AddCapabilities º¯Êý½«ËüÃÇÌí¼Óµ½ JVMTI »·¾³ÖУº

<table borderColor=#ffcc66 width="90%" align=center bgColor=#c8c7b9 border=1> <tr> <td>static jvmtiEnv *jvmti = NULL;
static jvmtiCapabilities capa;
jvmtiError error;

...

(void)memset(&capa, 0, sizeof(jvmtiCapabilities));
capa.can_signal_thread = 1;
capa.can_get_owned_monitor_info = 1;
capa.can_generate_method_entry_events = 1;
capa.can_generate_exception_events = 1;
capa.can_generate_vm_object_alloc_events = 1;
capa.can_tag_objects = 1;

error = (*jvmti)->AddCapabilities(jvmti, &capa);
check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities.");
...</td></tr></table>
¡¡¡¡´ËÍ⣬Agent_OnLoad º¯Êýͨ³£ÓÃÓÚ×¢²áʼþ֪ͨ¡£ÔÚ´ËʾÀýÖУ¬ÎÒÃÇÔÚʹÓà SetEventNotificationMode º¯ÊýµÄ Agent_OnLoad ÖÐÆôÓÃÁ˶à¸öʼþ£¬Èç VM Initialization Event¡¢VM Death Event ºÍ VM Object Allocation, ÈçÏÂËùʾ£º

<table borderColor=#ffcc66 width="90%" align=center bgColor=#c8c7b9 border=1> <tr> <td>error = (*jvmti)->SetEventNotificationMode
(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, (jthread)NULL);
error = (*jvmti)->SetEventNotificationMode
(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, (jthread)NULL);
error = (*jvmti)->SetEventNotificationMode
(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, (jthread)NULL);
check_jvmti_error(jvmti, error, "Cannot set event notification");

...</td></tr></table>
¡¡¡¡×¢Ò⣬ÔÚ´ËʾÀýÖУ¬NULL ÊÇ×÷ΪµÚÈý¸ö²ÎÊý´«µÝµÄ£¬Ëü¿ÉÒÔÈ«¾ÖµØÆôÓÃʼþ֪ͨ¡£Èç¹ûÐèÒª£¬¿ÉÒÔΪij¸öÌØÊâÏß³ÌÆôÓûò½ûÓÃijЩʼþ¡£

¡¡¡¡ÎÒÃÇΪÆä×¢²áµÄÿ¸öʼþ»¹¶¼±ØÐë¾ßÓÐÒ»¸öÖ¸¶¨µÄ»Øµ÷º¯Êý£¬µ±¸Ãʼþ·¢Éúʱ½«µ÷ÓÃËü¡£ÀýÈ磬Èç¹ûÒ»¸ö Exception ÀàÐ굀 JVMTI Event ·¢Éú£¬Ê¾Àý´úÀí»á½«Æä·¢Ë͵½»Øµ÷·½·¨ callbackException() ÖС£

¡¡¡¡Ê¹Óà jvmtiEventCallbacks ½á¹¹ºÍ SetEventCallbacks º¯Êý¿ÉÒÔÍê³É´ËÈÎÎñ£º

<table borderColor=#ffcc66 width="90%" align=center bgColor=#c8c7b9 border=1> <tr> <td>jvmtiEventCallbacks callbacks;
...

(void)memset(&callbacks, 0, sizeof(callbacks));
callbacks.VMInit = &callbackVMInit; /* JVMTI_EVENT_VM_INIT */
callbacks.VMDeath = &callbackVMDeath; /* JVMTI_EVENT_VM_DEATH */
callbacks.Exception = &callbackException;/* JVMTI_EVENT_EXCEPTION */
callbacks.VMObjectAlloc = &callbackVMObjectAlloc;/* JVMTI_EVENT_VM_OBJECT_ALLOC */

error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks,(jint)sizeof(callbacks));
check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks");

...</td></tr></table>
¡¡¡¡ÎÒÃÇ»¹½«ÉèÖÃÒ»¸öÈ«¾Ö´úÀíÊý¾ÝÇøÓòÒÔÔÚÕû¸ö´úÂëÖÐʹÓá£

<table borderColor=#ffcc66 width="90%" align=center bgColor=#c8c7b9 border=1> <tr> <td>/* Global agent data structure */
typedef struct {

¡¡/* JVMTI Environment */
¡¡jvmtiEnv *jvmti;
¡¡jboolean vm_is_started;

¡¡/* Data access Lock */
¡¡jrawMonitorID lock;
} GlobalAgentData;

static GlobalAgentData *gdata;</td></tr></table>
¡¡¡¡ÔÚ Agent_OnLoad º¯ÊýÖУ¬ÎÒÃÇÖ´ÐÐÒÔÏÂÉèÖãº

<table borderColor=#ffcc66 width="90%" align=center bgColor=#c8c7b9 border=1> <tr> <td>/* Setup initial global agent data area
* Use of static/extern data should be handled carefully here.
* We need to make sure that we are able to cleanup after
* ourselves so anything allocated in this library needs to be
* freed in the Agent_OnUnload() function.
*/

static GlobalAgentData data;
(void)memset((void*)&data, 0, sizeof(data));
gdata = &data;
...
/* Here we save the jvmtiEnv* for Agent_OnUnload(). */
gdata->jvmti = jvmti;
...</td></tr></table>
¡¡¡¡ÎÒÃÇÔÚ Agent_OnLoad() Öд´½¨Ò»¸öԭʼ¼àÊÓÆ÷£¬È»ºó°Ñ´úÂë VM_INIT¡¢VM_DEATH ºÍ EXCEPTION °ü×°ÓÚ JVMTI RawMonitorEnter() ºÍ RawMonitorExit() ½Ó¿Ú ¡£

<table borderColor=#ffcc66 width="90%" align=center bgColor=#c8c7b9 border=1> <tr> <td>/* Here we create a raw monitor for our use in this agent to
* protect critical sections of code.
*/

error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock));

/* Enter a critical section by doing a JVMTI Raw Monitor Enter */

static void
enter_critical_section(jvmtiEnv *jvmti)
{
¡¡jvmtiError error;

¡¡error = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock);
¡¡check_jvmti_error(jvmti, error, "Cannot enter with raw monitor");
}

/* Exit a critical section by doing a JVMTI Raw Monitor Exit */

static void
exit_critical_section(jvmtiEnv *jvmti)
{
¡¡jvmtiError error;
¡¡error = (*jvmti)->RawMonitorExit(jvmti, gdata->lock);
¡¡check_jvmti_error(jvmti, error, "Cannot exit with raw monitor");
}</td></tr></table>
¡¡¡¡Ð¶ÔØ´úÀíʱ£¬VM ½«µ÷Óà Agent_OnUnload¡£´Ëº¯ÊýÓÃÓÚÇåÀíÔÚ Agent_OnLoad ÆÚ¼ä·ÖÅäµÄ×ÊÔ´¡£

<table borderColor=#ffcc66 width="90%" align=center bgColor=#c8c7b9 border=1> <tr> <td>/* Agent_OnUnload: This is called immediately before the shared library
* is unloaded. This is the last code executed.
*/

JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{
¡¡/* Make sure all malloc/calloc/strdup space is freed */
}</td></tr></table>



¡ü·µ»ØĿ¼
ǰһƪ: ʵÏÖHibernate·ÖÒ³²éѯԭÀí½â¶Á
ºóһƪ: JavaÖÐËÄÖÖXML½âÎö¼¼ÊõÖ®²»ÍêÈ«²âÊÔ