工具软件   办公软件   操作系统   网络安全   设计在线   程序开发   教程宝典   软件下载   软件论坛
您的位置:软件 > 开发者网络 > 开发工具 > Java > 正文
用JVM工具接口创建调试和分析代理
[文章信息]
作者:
时间:2004-10-31
出处:sun
责任编辑:方舟
[文章导读]
Java 虚拟机工具接口提供了一种编程接口,允许软件开发人员创建软件代理以监视和控制 Java 编程语言应用程序
advertisement
热点推荐
· 禁止QQ登录的方法
· 给你的XML文件做个数字签名
· ImageReady制作“焰火”小动画
· Java加密和数字签名编程快速入门
· 在VB6中用命令行为模式控制GUI动作
[正文]

1 2 3 4 5  下一页

  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 进行了有关说明。

  本文阐述如何使用 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 <jvmti.h>。

  另外,代理必须包含一个名为 Agent_OnLoad 的函数,加载库时要调用这一函数。Agent_OnLoad 函数用于在初始化 Java virtual machine (JVM) 之前设置所需的功能。Agent_OnLoad 签名如下所示:

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
...

/* We return JNI_OK to signify success */
return JNI_OK;
}

  在我们的示例代码中,我们必须为将要使用的 JVMTI 函数和事件启用多种功能。一般情况下均需(在某些情况下必须)将这些功能添加到 Agent_OnLoad 函数中。有关每种函数或事件所需的功能的说明,参见 Java 虚拟机工具接口页。例如,要使用 InterruptThread 函数,can_signal_thread 功能必须为 true。我们把示例所需的全部功能都设置为 true,然后使用 AddCapabilities 函数将它们添加到 JVMTI 环境中:

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.");
...

  此外,Agent_OnLoad 函数通常用于注册事件通知。在此示例中,我们在使用 SetEventNotificationMode 函数的 Agent_OnLoad 中启用了多个事件,如 VM Initialization Event、VM Death Event 和 VM Object Allocation, 如下所示:

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");

...

  注意,在此示例中,NULL 是作为第三个参数传递的,它可以全局地启用事件通知。如果需要,可以为某个特殊线程启用或禁用某些事件。

  我们为其注册的每个事件还都必须具有一个指定的回调函数,当该事件发生时将调用它。例如,如果一个 Exception 类型的 JVMTI Event 发生,示例代理会将其发送到回调方法 callbackException() 中。

  使用 jvmtiEventCallbacks 结构和 SetEventCallbacks 函数可以完成此任务:

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");

...

  我们还将设置一个全局代理数据区域以在整个代码中使用。

/* Global agent data structure */
typedef struct {

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

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

static GlobalAgentData *gdata;

  在 Agent_OnLoad 函数中,我们执行以下设置:

/* 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;
...

  我们在 Agent_OnLoad() 中创建一个原始监视器,然后把代码 VM_INIT、VM_DEATH 和 EXCEPTION 包装于 JVMTI RawMonitorEnter() 和 RawMonitorExit() 接口 。

/* 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");
}

  卸载代理时,VM 将调用 Agent_OnUnload。此函数用于清理在 Agent_OnLoad 期间分配的资源。

/* 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 */
}


1 2 3 4 5  下一页

发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
相关内容焦点新闻
  • Java中四种XML解析技术之不完全测试
  • 编写跨平台Java程序的十二条规则
  • Hibernate 的原理与配置快速入门
  • 图解JBuilderX安装与实践
  • 用EJB开发在线课堂
  • 民营家电商排队造手机 设备商全面杀入
  • 英特尔澄清杨旭任职传闻 官方没宣布此消息
  • 国资委河北密制联通拆分方案
  • 垃圾邮件害人害企害国 清除垃圾邮件不手软
  • 中兴携手阿尔卡特 全球逐鹿CDMA
  • 用友总裁王文京:誓将ERP变成“大众消费”
  • 香港消费者委员会:数码相机最贵未必最好
  • 外电称中兴正评估西门子手机业务 或能并购
  • Advertisement

    天极无线


    奇妙科幻|美好风光|清风车影|漫画卡通|星座生肖|明星写真|动物世界
    老鼠爱大米
    挥着翅膀的女孩
    女人味
    栀子花开
    白月光
    刚刚好
    江南
    快乐崇拜
    亲爱的你怎么不在我身边
    小薇
    2002年的第一场雪
    有多少爱可以重来
    我的地盘
    七里香
    情人
     
    老鼠爱大米 老板电话
    冲动的惩罚 七里香
    我不是黄蓉 女生撒娇
    盛夏的果实 坚持到底
    孤单北半球 眉飞色舞
    挪威的森林 可爱女人
    最浪漫的事 老板电话

    CSEEK搜索