You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于PerfMark反射加载Logger避免类意外加载的疑问

关于PerfMark反射加载Logger避免类加载的疑问解答

代码修改背景

原代码与修改后的代码对比:

if (Boolean.getBoolean("io.perfmark.PerfMark.debug")) {
-          Logger.getLogger(PerfMark.class.getName()).log(Level.FINE, "Error during PerfMark.<clinit>", err);
+          // We need to be careful here, as it's easy to accidentally cause a class load.  Logger is loaded
+          // reflectively to avoid accidentally pulling it in.
+          // TODO(carl-mastrangelo): Maybe make this load SLF4J instead?
+          Class<?> logClass = Class.forName("java.util.logging.Logger");
+          Object logger = logClass.getMethod("getLogger", String.class).invoke(null, PerfMark.class.getName());
..
}

核心疑问

注释说明反射加载Logger是为了避免意外类加载,但测试发现无论反射还是直接调用,只有当if条件为真时才会触发Logger类的初始化(静态字段断点触发),if条件为假时都不会初始化Logger。想知道此处到底避免了哪个类的意外加载?

解答

这里要区分Java类加载的加载/解析阶段和初始化阶段:

  • 直接调用Logger.getLogger(...)时,编译阶段会将Logger和Level类标记为PerfMark类的依赖项。当JVM加载PerfMark类时,在链接阶段的解析步骤中,类加载器会尝试解析这些依赖类的符号引用,这会导致Logger、Level甚至其关联的日志类被提前加载(即使还没到初始化阶段)。
  • 而反射调用时,"java.util.logging.Logger"只是字符串常量,编译阶段不会产生对Logger类的依赖,JVM加载PerfMark类时,不会去解析Logger类的符号引用,也就不会提前加载Logger类。

你的测试断点是在静态字段(属于初始化阶段触发的逻辑),所以只有执行到代码时才会触发,但类的加载/解析可能在更早的PerfMark类加载阶段就发生了。PerfMark作为性能标记库,需要尽可能降低对应用启动性能的影响——哪怕只是加载而不初始化类,也会占用类加载器资源、增加启动时间。

这种反射方式的核心作用是:在默认关闭debug开关的场景下,完全避免Logger及相关日志类被提前加载/解析,只有当debug开关开启且代码执行到该分支时,才会触发Logger类的加载流程,最大程度减少不必要的启动开销。

内容的提问来源于stack exchange,提问作者Jane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 20:05:15