JVMTI
** JVMTI**:它到底能干什么,是怎么工作的,以及怎么使用它(尤其是在 Android 上的实际应用)。
一、JVMTI 到底是啥?为什么要用它?
JVMTI(Java Virtual Machine Tool Interface)是 Java 虚拟机提供的一套 原生接口(Native API),允许开发者编写 调试器、性能分析器、运行时监控工具 等低层次工具。它是 Java 平台中最强大、底层的调试接口之一。
在 Android 平台上,JVMTI 被广泛用于:
- Android Studio 的 Layout Inspector
- Memory Profiler
- App Startup Profiler
- 性能分析与热修复方案(如阿里 AndFix、腾讯 Matrix 等)
JVMTI 它不是写 App 用的,是给那些开发「调试器、性能分析工具、检测器、热修复系统」的人用的。
你可以把 JVMTI 想象成是:
JVM 的监听/操控台,可以用来偷偷观察、干预 Java 程序的运行过程。
比如你可以:
- 偷偷记录谁创建了对象、什么时候销毁的;
- 在某个方法开始前或结束后,插入自己的逻辑;
- 修改类的定义、重新注入代码;
- 看内存里有哪些对象,谁引用了它们;
- 拦截异常抛出事件;
- 检查是否有死锁或线程卡死。
二、JVMTI 能干什么?(详细功能+例子)
功能 | 能做什么 | 举例 |
---|---|---|
类和方法信息 | 获取或修改类、方法的结构信息 | 获取类名、字段、方法签名;替换 class 定义 |
对象监控 | 追踪内存中对象的生命周期 | 哪个线程创建了它?被谁引用? |
内存分析 | 获取堆栈快照、对象大小、引用链 | 做内存泄漏分析、堆视图 |
性能采样 | 定时查看当前调用栈 | 看应用卡顿在哪个函数 |
线程监控 | 线程创建、销毁、状态变化 | 看是否发生死锁 |
异常追踪 | 拦截异常抛出 | 统计某异常发生的频率 |
代码注入 | 动态替换类字节码(Redefine) | 做热修复,不重启替换 class |
三、工作原理简述(带图解)
+-----------------------+
| Android Studio |
| (或你的分析工具) |
+-----------+-----------+
|
[加载 Agent]
v
+-----------------------+
| JVMTI Agent.so | ← 你写的 C/C++ 插件
+-----------+-----------+
|
[回调注册]
v
+-----------------------+
| ART / JVM | ← Android Runtime
+-----------------------+
步骤:
- 你编写一个 native 库(.so),这个库使用 JVMTI 提供的 C 接口。
- 在 App 启动时,这个库通过 -agentpath 或 Attach API 被加载到进程里。
- 你注册感兴趣的事件,比如“某个方法被调用”、“类被加载”。
- 当 JVM 发生这些事件,JVMTI 就会 回调你写的 native 函数。
- 你可以获取数据、打印日志、甚至修改类结构。
总结来说就是:
- Android Studio 加载 JVMTI Agent 到目标进程
- Agent 注册回调方法,监听 JVM 事件
- ART Runtime 触发事件,调用 Agent 逻辑
- Agent 可以通过 JNI 操作 Java 层数据
在 Android 中的常用函数(C/C++)
jvmtiEnv* jvmti;
jvmti->SetEventNotificationMode(...); // 开启某类事件通知
jvmti->GetLoadedClasses(...); // 获取已加载类
jvmti->GetObjectSize(...); // 获取对象大小
jvmti->RedefineClasses(...); // 替换类定义
常用事件(JVMTI Event)
事件名 | 描述 |
---|---|
JVMTI_EVENT_VM_INIT | 虚拟机启动完成 |
JVMTI_EVENT_CLASS_LOAD | 类加载 |
JVMTI_EVENT_METHOD_ENTRY | 方法调用 |
JVMTI_EVENT_EXCEPTION | 异常捕获 |
JVMTI_EVENT_GARBAGE_COLLECTION_START | GC 开始 |
JVMTI_EVENT_OBJECT_FREE | 对象回收 |
使用门槛
限制项 | 描述 |
---|---|
Android 8.0+ | Android 从 8.0(API 26)才开始支持 JVMTI |
Native 实现 | 需要编写 .so 库,且具备 JNI 基础 |
Debuggable App | 要调试的 App 通常需要是 debuggable 的 |
权限敏感 | 某些事件监控需要系统权限或 root |
四、实际使用场景举例(以 Android 为主)
1. Android Studio 的 Layout Inspector
使用 JVMTI 遍历内存里的所有 Activity,找到当前显示的界面和 View 树(通过反射 Java 对象)。
2. Memory Profiler
通过 JVMTI 触发 堆快照,分析某个对象是否还被引用、大小是多少、谁持有引用。
3. 热修复(Redefine Classes)
比如你线上发布的 App 有 bug,可以用 JVMTI 把某个类在内存中的定义替换掉(如果类没有被 AOT 编译或内联)。
五、在 Android 上怎么使用 JVMTI?
1. 开启 JVMTI 支持(8.0+)
你必须在 Android 8.0(API 26)以上,且 App 是 debuggable=true。
2. 编写 agent(C/C++)
// agent.cpp
#include <jvmti.h>
#include <jni.h>
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
jvmtiEnv* jvmti;
vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_1);
// 打开事件,比如类加载
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, nullptr);
// 注册事件处理器...
return JNI_OK;
}
你需要用 CMake 编译这个为 .so 库。
3. 启动时加载这个 Agent
你可以在 Android 中使用如下方式:
Debug.attachJvmtiAgent("/data/local/tmp/libagent.so", null, null);
注意:这个 API 需要 debuggable=true 和系统权限。
六、使用成本与限制
项目 | 说明 |
---|---|
学习成本高 | 需要掌握 C/C++、JNI、JVM 内部结构 |
系统权限 | 有些能力需要 root 权限或系统签名 App |
兼容性问题 | Android 上部分 JVMTI 能力被限制(比如 Redefine 限制多) |
性能开销 | 监控事件本身会带来开销,需谨慎使用 |
七、总结一句话
JVMTI 是 JVM/ART 的“监听钩子”,能让你动态观察、分析、甚至修改 Java 程序的运行行为,是开发调试器、Profiler、热修复系统的核心工具。