BTrace脚本不生效的根本原因是JVM未启用调试支持或版本不兼容;需确认启动参数、JDK匹配、沙箱限制及正确使用@OnMethod等。

为什么 BTrace 脚本没生效,连 println 都不输出?
根本原因通常是 JVM 启动时没开调试支持,或者 BTrace 版本和 JDK 不兼容。BTrace 依赖 -javaagent 和 JVMTI 接口,JDK 9+ 默认禁用部分 JVMTI 功能,且 OpenJDK 17+ 已移除对 BTrace 的原生支持。
- 确认 JVM 启动参数包含
-XX:+UnlockDiagnosticVMOptions -XX:+AllowEnhancedClassRedefinition(JDK 8 必加;JDK 11+ 可能还需--add-exports java.base/jdk.internal.vm=ALL-UNNAMED) - BTrace 2.x 仅支持 JDK 8~11;JDK 17+ 基本不可用,别硬试——会静默失败,无日志、无报错
-
BTraceRunner必须用与目标 JVM 相同的 JDK 运行,混用 JRE/JDK 或不同厂商(如 Zulu vs. Temurin)会导致ClassNotFoundException - 脚本里避免调用任意非
java.lang.*外部类,BTrace 沙箱禁止加载第三方类,否则直接跳过织入
如何写一个安全可用的 @OnMethod 监控脚本?
BTrace 的核心是静态字节码注入,不是代理或 AOP,所以方法签名必须完全匹配,且不能修改原逻辑。稍有偏差就织入失败,还查不到原因。
- 目标类名必须写全限定名,比如
"java.util.ArrayList",不能写"ArrayList";内部类用$分隔,如"com.example.Service$Inner" -
@OnMethod的clazz和method是必填项,location = @Location(Kind.RETURN)才能取到返回值,但注意:返回值为void时@Return参数会报错 - 只允许用
print/println输出,且输出内容必须是字符串拼接或基本类型,不能调用toString()(可能触发新对象分配,被沙箱拦截) - 示例:监控
HashMap.get调用耗时
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class HashMapGetTracer {
@OnMethod(
clazz = "java.util.HashMap",
method = "get",
location = @Location(Kind.RETURN)
)
public static void onGet(@Self Object self, String key, @Return Object result) {
println(strcat("get(", strcat(str(key), "): ")));
println(str(result));
}
}
BTrace 和 Arthas、JFR 对比时该选哪个?
不是“哪个更好”,而是“哪个不崩”。BTrace 在生产环境已属高危操作,尤其 JDK 11+ 后几乎退场。
-
BTrace:零依赖、纯 agent,但稳定性差,JDK 升级后极易失效;适合 JDK 8 下临时排查,不建议集成进监控体系 -
Arthas:watch/trace命令更友好,支持 JDK 8~21,热更新脚本、可卸载,出问题 kill session 就行,日常诊断首选 -
JFR(Java Flight Recorder):JDK 自带,低开销,适合长期采集 GC、锁、方法采样等,但无法自定义逻辑,也不能改行为 - 真实场景中,BTrace 常被误用于“想改点东西”,比如想记录某个字段值——这超出它能力边界,该换
Byte Buddy或Java Agent自研
运行 btrace 命令时提示 NoClassDefFoundError: sun/jvm/hotspot/HotSpotAgent
这是 BTrace 试图用 SA(Serviceability Agent)attach 本地进程导致的,SA 在 JDK 9+ 中默认关闭,且需要额外 debuginfo 支持,基本不可用。
立即学习“Java免费学习笔记(深入)”;
- 不要用
btrace <pid> script.java直连本地进程,改用btracec编译 +btrace加载 agent 方式 - 编译命令:
btracec -d /tmp/classes MyScript.java;加载命令:btrace -p 2020 <pid> /tmp/classes/MyScript.class(-p指定端口,避免权限问题) - 如果目标 JVM 启用了
-XX:+DisableAttachMechanism,BTrace 完全无法 attach,需重启 JVM 并去掉该参数 - Linux 下若提示
Permission denied,检查/proc/sys/kernel/yama/ptrace_scope是否为 0;非 root 用户 attach 需设为 0 或改用同一用户启动目标 JVM
trace,它报错清楚、能撤回、不崩 JVM——BTrace 留给离线复现和 JDK 8 遗留系统更稳妥。










