ClassNotFoundException是类加载阶段未找到字节码的检查异常;NoClassDefFoundError是类已加载但初始化失败后被标记不可用的错误,分别发生在加载阶段和初始化阶段。

排查 JVM 类加载异常,关键不是“用哪个工具”,而是搞清异常类型、定位加载阶段、验证类是否真被加载。工具只是帮你看到真实现场的放大镜,不是自动解题器。
先看报错类型,决定排查方向
ClassNotFoundException、NoClassDefFoundError、NoSuchMethodError 看似相似,但根源完全不同:
-
ClassNotFoundException:类根本没被任何类加载器找到——查类路径、jar 是否真在、类名拼写、是否被排除(如 Maven
) -
NoClassDefFoundError:类曾被加载过,但在初始化时失败(比如静态块抛异常),或运行期该类被卸载/不可见——重点查
和依赖传递性 - NoSuchMethodError:类存在,但方法签名不匹配(参数、返回值、泛型擦除后不同)——说明编译用的版本和运行用的 jar 版本不一致
用 -verbose:class 快速确认类是否加载
启动 JVM 时加上 -verbose:class,JVM 会在控制台逐行打印每个被加载的类及其加载器,例如:
[Loaded org.example.Main from file:/app/classes/]
[Loaded org.apache.commons.codec.binary.Base64 from file:/app/lib/commons-codec-1.15.jar]
如果目标类没出现在日志里,说明它压根没被触发加载;如果出现了但后续仍报错,问题大概率出在链接或初始化阶段。
用 Arthas 的 classloader + sc 定位加载器归属
线上环境无法加启动参数?用 Arthas 实时诊断:
-
classloader -t:查看当前类加载器树,确认双亲委派链是否被破坏 -
sc -d *JsonUtil*:搜索已加载的类,显示它的 ClassLoader 实例 ID -
classloader -c:让指定加载器尝试重载该类字节码(验证路径是否可达)-r com/company/core/utils/JsonUtil.class
特别有用的是发现“同名类被不同加载器加载”——比如 JsonUtil 被 PluginClassLoader 加载了一次,又被 AppClassLoader 加载了另一次,两者在 JVM 内互不兼容,强制转型就会失败。
用 jcmd + jhsdb 查看运行期类状态
当怀疑类加载中途卡住或元空间异常时:
-
jcmd:检查元空间(Metaspace)使用量是否接近上限VM.native_memory summary -
jhsdb jmap --heap --pid:查看类加载器实例数量,暴增往往意味着类加载泄漏(如热部署未清理旧加载器) - 配合
jstack看线程栈,确认是否阻塞在ClassLoader.loadClass()或Class.forName()调用上
不复杂但容易忽略











