轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

    • 核心

    • 并发

    • 经验

    • JVM

      • JVM体系
      • 深入理解JIT编译器
      • JVMTI介绍
        • JVMTI功能
          • 1 线程管理
          • 2 堆内存分析
          • 3 类加载器跟踪
          • 4 字节码插装
          • 5 事件通知
          • 6 性能监控
          • 7 异常跟踪
          • 8 垃圾回收管理
        • 使用JVMTI的示例
          • 1 编写一个简单的JVMTI Agent
          • 2 使用JVMTI获取线程信息
        • 常见的JVMTI工具
          • 1 VisualVM
          • 2 YourKit Java Profiler
          • 3 JProfiler
          • 4 Java Flight Recorder (JFR)
        • 与Instrument API的关系
        • 总结
      • 从Hotspot到GraalVM
    • 企业应用

  • Spring

  • 其他语言

  • 工具

  • 后端
  • Java
  • JVM
轩辕李
2023-05-03
目录

JVMTI介绍

JVMTI(Java Virtual Machine Tool Interface)是Java虚拟机(JVM)提供的一组用于构建Java虚拟机工具的接口。

它允许开发人员实现诸如调试器、分析器和监视工具等功能。

JVMTI为JVM与工具之间提供了一个标准化的通信接口。

# JVMTI功能

# 1 线程管理

JVMTI可以获取有关线程的信息,例如线程名、线程组、线程状态等。此外,JVMTI还允许工具暂停、恢复或停止线程。

# 2 堆内存分析

JVMTI允许工具检查和分析JVM堆内存的使用情况。这可以帮助开发人员找到内存泄漏、内存浪费等问题。

# 3 类加载器跟踪

JVMTI可以跟踪JVM加载的所有类及其关联的类加载器。这有助于分析类加载过程中的问题,例如类冲突、类加载失败等。

# 4 字节码插装

JVMTI支持在运行时修改已加载类的字节码。这使得工具可以在不修改原始代码的情况下植入额外的功能,例如插入性能计数器、代码覆盖率分析等。

# 5 事件通知

JVMTI允许工具订阅各种JVM事件,如线程启动、线程终止、类加载、类卸载、方法入口/出口等。这使得工具可以实时监控JVM的运行状况。

# 6 性能监控

JVMTI提供了许多用于性能监控的接口,如获取CPU使用率、内存使用情况、垃圾回收次数等。这使得工具可以跟踪应用程序的性能,并为优化提供有价值的信息。

# 7 异常跟踪

JVMTI可以追踪Java应用程序中发生的异常事件。通过这些接口,开发人员可以查看异常的详细信息,如异常类型、异常消息、调用堆栈等。

# 8 垃圾回收管理

JVMTI支持监控和管理垃圾回收(GC)过程。例如,工具可以强制执行垃圾回收、获取GC统计信息等。

# 使用JVMTI的示例

# 1 编写一个简单的JVMTI Agent

我们将创建一个简单的JVMTI Agent,用于打印JVM加载的所有类名。首先,我们需要创建一个名为jvmti_agent.c的C文件:

#include <jvmti.h>
#include <stdio.h>

// JVM加载类时的回调函数
static void JNICALL
ClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv *jni_env, jclass class_being_redefined,
                  jobject loader, const char *name, jobject protection_domain,
                  jint class_data_len, const unsigned char *class_data,
                  jint *new_class_data_len, unsigned char **new_class_data) {
    printf("Loaded class: %s\n", name);
}

JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
    jvmtiEnv *jvmti;
    jvmtiCapabilities capabilities;
    jvmtiEventCallbacks callbacks;

    // 获取JVMTI环境
    (*jvm)->GetEnv(jvm, (void **)&jvmti, JVMTI_VERSION_1_0);

    // 初始化capabilities并启用ClassFileLoadHook事件
    memset(&capabilities, 0, sizeof(capabilities));
    capabilities.can_generate_all_class_hook_events = 1;
    (*jvmti)->AddCapabilities(jvmti, &capabilities);

    // 注册回调函数
    memset(&callbacks, 0, sizeof(callbacks));
    callbacks.ClassFileLoadHook = &ClassFileLoadHook;
    (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks));

    // 启用ClassFileLoadHook事件
    (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);

    return JNI_OK;
}

接下来,我们需要使用gcc或其他C编译器将此代码编译为共享库(例如,在Linux上为.so文件,在Windows上为.dll文件)。

gcc -shared -o libjvmti_agent.so jvmti_agent.c -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -fPIC

现在,我们可以使用-agentpath参数运行Java应用程序,并加载我们的JVMTI Agent:

java -agentpath:/path/to/libjvmti_agent.so MyJavaApp

运行此命令后,JVM将加载我们的JVMTI Agent,并在加载每个类时打印类名。这只是一个简单的示例,实际上JVMTI Agent可以执行许多高级任务,如性能分析、调试、监控等。

# 2 使用JVMTI获取线程信息

接下来,我们将创建一个JVMTI Agent,用于获取当前运行的Java线程信息。首先,我们需要创建一个名为jvmti_threads.c的C文件:

#include <jvmti.h>
#include <stdio.h>

// 获取并打印线程信息的函数
static void JNICALL
list_threads(jvmtiEnv *jvmti) {
    jthread *threads;
    jint thread_count;
    jvmtiError err;

    // 获取所有线程
    err = (*jvmti)->GetAllThreads(jvmti, &thread_count, &threads);
    if (err != JVMTI_ERROR_NONE) {
        printf("ERROR: Unable to get all threads\n");
        return;
    }

    printf("Total threads: %d\n", thread_count);

    // 遍历所有线程并打印信息
    for (int i = 0; i < thread_count; i++) {
        jvmtiThreadInfo thread_info;
        err = (*jvmti)->GetThreadInfo(jvmti, threads[i], &thread_info);
        if (err == JVMTI_ERROR_NONE) {
            printf("Thread %d: %s\n", i, thread_info.name);
            (*jvmti)->Deallocate(jvmti, (unsigned char *)thread_info.name);
        } else {
            printf("ERROR: Unable to get thread info\n");
        }
    }

    // 释放线程数组
    (*jvmti)->Deallocate(jvmti, (unsigned char *)threads);
}

JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
    jvmtiEnv *jvmti;

    // 获取JVMTI环境
    (*jvm)->GetEnv(jvm, (void **)&jvmti, JVMTI_VERSION_1_0);

    // 获取并打印线程信息
    list_threads(jvmti);

    return JNI_OK;
}

与上一个示例类似,我们需要使用C编译器将此代码编译为共享库:

gcc -shared -o libjvmti_threads.so jvmti_threads.c -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -fPIC

现在,我们可以使用-agentpath参数运行Java应用程序,并加载我们的JVMTI Agent:

java -agentpath:/path/to/libjvmti_threads.so MyJavaApp

运行此命令后,JVM将加载我们的JVMTI Agent,并在启动时打印所有当前运行的Java线程信息。

# 常见的JVMTI工具

许多常见的Java性能和调试工具都使用了JVMTI接口。以下是一些广泛使用的JVMTI工具:

# 1 VisualVM

VisualVM是一个用于监视、分析和调试Java应用程序的工具。它提供了对运行中的Java虚拟机的实时信息,包括线程、内存、类加载器、垃圾回收等。VisualVM还包含了一些用于性能分析的功能,如CPU和内存分析器,以及用于调试的功能,如线程和监视器跟踪。VisualVM使用JVMTI接口与JVM进行通信。

# 2 YourKit Java Profiler

YourKit Java Profiler是一个强大的性能分析和调试工具,用于分析Java应用程序的CPU、内存、线程等方面的性能。YourKit Java Profiler使用JVMTI接口与JVM进行通信,以收集详细的性能数据。它还提供了一个易于使用的图形界面,用于查看和分析收集到的数据。

# 3 JProfiler

JProfiler是另一个广泛使用的Java性能分析和调试工具。它提供了对Java应用程序的实时性能监控和分析,包括CPU、内存、线程等。JProfiler使用JVMTI接口与JVM进行通信,并提供了一个易于使用的图形界面,用于查看和分析收集到的数据。

# 4 Java Flight Recorder (JFR)

Java Flight Recorder(JFR)是一个内置于Java虚拟机的诊断和分析工具,可用于收集应用程序和JVM的详细性能数据。JFR使用JVMTI接口与JVM进行通信,并生成详细的事件记录文件,可用于离线分析。这些事件记录文件可以使用JDK内置的Java Mission Control(JMC)工具进行分析。

# 与Instrument API的关系

在Java运行期动态能力中介绍到Java Agent,底层其实就是借助JVMTI来进行完成的。

从Java SE 5开始,提供了Instrumentation接口(java.lang.instrument)来编写Agent。

Java Instrument是一种高级别的Java工具接口,基于JVMTI和反射机制,可以更加方便地进行Java字节码操作和Java应用程序监控。

Java Instrument可以让开发人员通过Java代理(agent)向Java应用程序注入字节码,并在程序运行时进行修改、监控和控制。

相对于JVMTI,Java Instrument更加易用,而且可以直接使用Java语言进行开发。

# 总结

JVMTI(Java Virtual Machine Tool Interface)是Java虚拟机提供的一组用于构建Java虚拟机工具的接口。

JVMTI允许开发人员实现诸如调试器、分析器和监视工具等功能。

通过学习JVMTI,您可以更好地理解这些工具的工作原理,并可能为您的Java应用程序提供更深入的诊断和分析功能。

祝你变得更强!

编辑 (opens new window)
#JVMTI
上次更新: 2023/06/14
深入理解JIT编译器
从Hotspot到GraalVM

← 深入理解JIT编译器 从Hotspot到GraalVM→

最近更新
01
Spring Boot版本新特性
09-15
02
Spring框架版本新特性
09-01
03
Spring Boot开发初体验
08-15
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式