怎么利用 ASM 框架在类加载期动态修改字节码以实现全自动的方法耗时埋点

风静君_1856

风静君_1856

2026-04-27

413人浏览

原创

不能用classfiletransformer实现全自动耗时埋点,因其受jvm重定义限制(不可增删方法/字段、不可改签名),android非debuggable进程禁用且art不支持,首次加载类无法拦截,性能开销大。

怎么利用 asm 框架在类加载期动态修改字节码以实现全自动的方法耗时埋点

不能在类加载期直接用 ASM 动态修改字节码实现全自动耗时埋点——ClassFileTransformer 虽然支持运行时字节码修改,但会触发 JVM 的类重定义限制(如不能新增/删除方法、不能改签名),且对 java.* 和启动类加载器加载的类无效,实际埋点几乎必然失败。

为什么不能靠 ClassFileTransformer 做全自动耗时埋点

很多人一上来就查 Instrumentation.addTransformer(),以为加个 ClassFileTransformer 就能无感插桩。现实是:

  • JVM 对 retransformClasses() 有严格约束:只能修改已有方法体(Code 属性),不能增删字段、方法,也不能改方法签名或异常表 —— 而耗时统计需要插入 System.nanoTime() 开始/结束调用,还常依赖静态计数器或 Map 缓存,这些都得提前准备好字段或辅助方法
  • Android 上根本不可用:Instrumentation 在非 debuggable 进程里被禁用,且 ART 不支持运行时 retransform(从 Android 8.0 起彻底移除)
  • 即使在桌面 JVM,首次加载类时无法拦截(transform() 只对后续 defineClass 或 retransform 生效),导致 Application 类、Activity 生命周期等关键入口漏埋
  • 性能开销不可控:每个类加载都走 transformer,大量反射调用 + 字节码解析,冷启动拖慢 20%+ 很常见

真正可行的路径:编译期插桩 + Transform Action(AGP 7.0+)

Android 官方明确废弃了旧版 Transform API,现在必须用 TransformAction 配合 AsmClassVisitorFactory。这是目前唯一稳定、可控、能覆盖全量方法的方案:

ARC Lab
ARC Lab

一款提供AI人像处理、图像增强和智能抠图等能力的视觉处理工具集合,方便用户在线体验多种图片优化功能。

下载
  • AsmClassVisitorFactory 是 AGP 封装的轻量入口,它自动帮你处理 class 文件读写、多线程安全、增量编译跳过逻辑,不用手动写 ClassReader/ClassWriter
  • 你只需继承 AsmClassVisitorFactory,重写 createClassVisitor(),返回一个自定义 ClassVisitor,在里面用 visitMethod() 拦截目标方法
  • 耗时逻辑建议封装成独立工具类(如 TimingMonitor.recordStart(String) / recordEnd(String)),避免在每个方法里重复生成时间戳指令;ASM 插入时只调这两句即可
  • 注意过滤系统类和第三方 SDK:通过 className.startsWith("android.") 或白名单机制跳过,否则可能破坏 OkHttp、Retrofit 等库的字节码结构

ASM 插入耗时代码时最容易踩的坑

手写 MethodVisitor 插入前后计时,看着简单,实际极易出错:

  • 别硬编码局部变量索引:方法参数数量、是否为 static、是否含 long/double(占两个 slot)都会影响 index,必须用 AdviceAdapter 自动管理栈和变量槽位
  • 不要在 visitCode() 后直接 visitInsn(Opcodes.LRETURN) 这类指令:需先调用 visitVarInsn(Opcodes.LSTORE, slot) 保存起始时间,再在方法末尾 visitVarInsn(Opcodes.LLOAD, slot) 读取,否则栈不平衡导致 VerifyError
  • Android 上慎用 System.nanoTime():部分低端机型该方法耗时高达 1~2μs,反而污染统计结果;可改用 SystemClock.uptimeMillis()(精度 10~15ms,但更轻量)
  • 如果目标方法本身抛异常,你的 recordEnd() 必须放在 finally 块里 —— 这意味着要插入 TRYCATCHBLOCK,不是简单追加几行指令,得用 LocalVariablesSorter + TraceMethodVisitor 辅助分析控制流

最麻烦的不是插桩本身,而是如何让耗时数据能被业务层消费:你得在插桩时动态注入唯一 methodId(比如 className + "." + methodName + descriptor 的 hash),再确保这个 ID 能和后台埋点 schema 对齐。漏掉这步,所有字节码都插对了,数据也传上去了,但查不到对应方法 —— 这种问题线上根本没法 debug。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

字节

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

10637

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

7762

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

6752

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1144

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

948

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1396

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2809

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20111

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1235

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程