Arthas classloader + sc 实战:JVM 类加载与手动加载

简介: ClassNotFoundException 不一定是类不存在。Arthas classloader 和 sc,查 JVM 加载了哪些类、手动加载没加载的类

大家好,我是程序员天天困。

这是「Arthas 线上诊断实战」系列第 6 篇。上一篇 Profiler 火焰图 解决的是 CPU 热点定位,这篇讲 Arthas classloader 和 sc——回到一个更基础但更让人懵的场景:线上突然报 ClassNotFoundException,代码明明就在那儿,依赖也引了,JVM 偏偏说找不到。点个收藏,我们直接上手。

一、ClassNotFoundException 不是代码写错了,是类没被加载

线上最常见的类加载问题,不是类不存在,而是类没被 JVM 加载过。

这种问题有一个非常典型的场景:一个报表服务引入了工具类 ReportUtils,本地跑得好好的,上预发环境突然报 ClassNotFoundException。第一反应查 pom 依赖——在的;反编译 jar——class 也在。折腾快一个小时才发现,那个类从来没被加载过,因为预发环境走的代码路径根本没触发到它。

这就引出一个很多人没意识到的真相:你写在项目里的类、maven 引进来的依赖,不等于已经被 JVM 加载了。 类是「用到才加载」的,没用到的类可能永远躺在 jar 里不进内存。

那问题就变成两个:

  1. 当前 JVM 到底加载了哪些类?
  2. 能不能手动让 JVM 加载某个类?

Arthas 给了两个命令分别对付这两件事:sc 搜类classloader 管类加载器

二、类什么时候被加载:不是写在项目里就一定加载

类的加载是懒加载,JVM 不会一启动就把所有 class 全塞进内存,而是「用到才加载」。

什么是「用到」?JVM 规范里类的主动使用场景主要包括这几种:

主动使用场景 举例
new 实例化 new ReportUtils()
调用静态方法 ReportUtils.format(...)
访问静态字段 ReportUtils.DEFAULT_FORMAT
反射调用 Class.forName("com.ttk.ReportUtils")
子类被加载 父类会先被加载
main 方法所在的类 启动时自动加载

我用一个简单的示例场景说明。假设有个 com.ttk.ReportUtils 类,里面只有一个静态代码块:

// 示例:静态代码块在类被加载时执行
package com.ttk;

public class ReportUtils {
   
    static {
   
        System.out.println("ReportUtils 被加载了!");
    }
}

然后有个启动类 Main

// 示例:Main 类引用了 ReportUtils 但没主动使用
package com.ttk;

public class Main {
   
    public static void main(String[] args) {
   
        System.out.println("Hello World");
        // 注意:这里没有 new ReportUtils(),也没调它的静态方法
    }
}

跑一下,输出只有 Hello WorldReportUtils 被加载了! 这行不会出现。为什么?因为 Main 只是和 ReportUtils 在同一个包里,并没有主动使用它——JVM 没有理由加载它。

相同的逻辑也出现在依赖上:你用 maven 引了一个坐标,jar 包里的所有类也不会全部加载,只有被实际用到的才会进 JVM。

这就解释了为什么 ClassNotFoundException 会在线上突然冒出来--代码在 jar 里,但运行时恰好没走到那条加载路径。

三、Arthas sc 命令:搜出 JVM 里到底加载了哪些类

sc(Search Class)是 Arthas 用来搜索已加载类的命令,它能告诉你 JVM 里现在到底有哪些类。

Arthas sc(Search Class):Arthas 命令,按类名模糊匹配搜索 JVM 已加载的类,支持查看类加载器、字段、方法等详细信息。你可以把它理解为「JVM 内存里的类文件搜索器」。

前提还是先把 Arthas Attach 到目标 JVM(前面几篇讲过,java -jar arthas-boot.jar 选进程进到 [arthas@PID]$)。进来之后,搜 com.ttk 包下的所有类:

sc com.ttk.*

从输出结果能直观看到:只有 Main 被加载了,ReportUtils 没出现。

sc 支持模糊匹配,* 通配符搜包路径很方便。想看某个类的详细信息——是哪个 ClassLoader 加载的、有哪些字段方法——加 -d

sc -d com.ttk.Main

输出里有个关键字段叫 classLoaderHash,这是一串十六进制的 hash 值,代表加载这个类的类加载器。记住这个 hash,后面 classloader 手动加载类的时候要用

可能有人会问:sc 和 jad 有什么区别?

jad 是把已加载的 class 反编译成源码给你看;sc 是列出 JVM 里有哪些类被加载了,看的是「有没有」而不是「源码长啥样」。排查类加载问题,先用 sc 看类在不在,再用 jad 看源码对不对。

sc 的完整用法见 Arthas sc 官方文档,支持 -E 正则匹配、-f 查看字段、-m 查看方法等,日常排查 sc 类名sc -d 类名 就够用了。

四、Arthas classloader 命令:查看当前所有类加载器

想手动加载类,得先搞清楚 JVM 里有哪些类加载器,classloader 命令就是干这个的。

Arthas classloader:Arthas 命令,查看 JVM 内所有 ClassLoader 实例、加载的类数量、层级关系,并支持手动加载类。你可以把它理解为「JVM 类加载器的管理员」。

类加载器是 JVM 加载类的执行者。JVM 里不止一个类加载器,它们按双亲委派模型分层协作:

Arthas classloader 双亲委派模型:Bootstrap → Platform(JDK 9+ 替代 Extension)→ AppClassLoader,Arthas attach 后还会出现 ArthasClassloader

核心逻辑就一句话:收到加载请求时,先交给父加载器去加载,父加载器搞不定才自己加载。 这样保证 java.lang.String 永远由 Bootstrap 加载,不会被你的自定义 ClassLoader 篡改。

双亲委派模型:JVM 类加载器的分层委派机制,子加载器收到请求先委托父加载器加载,父加载器加载不了才自己加载。你可以理解为「有事先请示上级,上级处理不了再自己来」。

用 classloader 命令查看当前 JVM 有哪些类加载器:

classloader

输出会列出每个 ClassLoader 的 hash、类型和已加载的类数量。加 -t 能看层级关系:

classloader -t

树形输出里能直观看到层级关系(以 JDK 11 为例):

  • BootstrapClassLoader 在最顶层,C++ 实现,没有父加载器。
  • PlatformClassLoader(JDK 8 叫 ExtClassLoader,JDK 9+ 改名)挂在 Bootstrap 下。
  • AppClassLoader 挂在 PlatformClassLoader 下,负责加载你 classpath 下的类。
  • 注意:因为 Arthas attach 到了这个 JVM,所以输出里还会多一个 ArthasClassloader,和 AppClassLoader 平级挂在 PlatformClassLoader 下 —— 这是 Arthas 用来加载自身命令类的。

五、手动加载一个类:classloader --load 实战

前面铺了这么多,现在到正题:用 classloader --load 把一个没被加载的类手动塞进 JVM。

为什么要手动加载?排查类加载问题时,有时需要验证「这个类能不能被加载」「加载后行为对不对」,而不想为了触发加载去改业务代码、走一遍完整调用链。classloader --load 给你一条直通路径。

操作分两步:

第 1 步,拿到目标 ClassLoader 的 hash。classloader 命令列出所有类加载器,找到你要用的那个(通常是 AppClassLoader 或业务自定义的 ClassLoader),记下它的 hash 值,比如 1dbd16a6

第 2 步,用 --load 指定 hash 和类全名:

classloader -c 1dbd16a6 --load com.ttk.ReportUtils

拆开看:

  1. -c 1dbd16a6:指定用哪个 ClassLoader 加载(hash 来自上一步)。
  2. --load com.ttk.ReportUtils:要加载的类全限定名。

执行成功后,终端没有报错就是加载成功了。再用 sc 验证一下:

sc com.ttk.ReportUtils

这次 ReportUtils 出现在输出里了——说明它已经被 JVM 加载进去了。

有个细节要注意:-c 后面跟的 hash 必须是真实存在的 ClassLoader hash,写错了会报 classloader not found。这个 hash 每次启动 JVM 都可能不一样,别想偷懒记死值。

六、sc + classloader 怎么和前面的命令搭配

sc 和 classloader 解决的是「类在不在 JVM 里」的问题,和前面几篇的命令是配合关系,不是替代。

六篇写下来,整个排查链路已经比较完整了:

阶段 优先命令 你在解决什么
入参 / 返回对不对 watch 结果对错
走了哪条分支、哪层慢 trace 路径与耗时
没请求也要看对象状态 vmtool 堆内实例
已定位到方法体写错 mc + retransform 在线换逻辑
CPU 飙高找全局热点 profiler 性能瓶颈
类没被加载、手动加载 sc + classloader 类加载问题
确认字节码是否已换 jad 反编译核对

推荐排查顺序:报 ClassNotFoundException 先用 sc 看类在不在 JVM 里 -> 不在就用 classloader 查有哪些类加载器、拿到 hash -> 用 classloader --load 手动加载 -> sc 再验一次确认加载成功。 这条链路走完,类加载问题基本就闭环了。

结语

Arthas classloader 和 sc 解决的是工具箱里最基础但最容易被忽略的一环——「类到底加载没加载」。ClassNotFoundException 不一定是类不存在,很多时候是 JVM 没走到加载路径。sc 帮你查 JVM 里有哪些类,classloader 帮你查有哪些类加载器、还能手动把类塞进去,两者配合,类加载问题基本不用再靠猜。

下一篇我会写这个系列的 ognl:Arthas 里最灵活也最容易上头的表达式引擎,一行命令在运行时调任意方法、访问私有字段。本文命令参数以 Arthas sc 官方文档Arthas classloader 官方文档 为准,版本更新了以官网为准。


我是程序员天天困,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你有没有在线上踩过 ClassNotFoundException 的坑?用过 Arthas classloader 手动加载吗?

相关文章
|
8天前
|
人工智能 JSON 安全
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
阿里云AI安全产品联动防御Fastjson攻击
2188 12
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
|
8天前
|
云安全 人工智能 安全
|
8天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max-Preview深度全解析:2.4万亿参数旗舰MoE模型+Token Plan限时优惠完整落地指南
2026年7月,全新旗舰级混合专家大模型Qwen3.8-Max-Preview正式开放抢先体验,作为通义千问Qwen3系列规格最高、综合推理能力顶尖的新一代模型,该模型总参数量达到2.4万亿(2.4T),是当前线上可调用的原生多模态旗舰模型,综合推理水准对标海外顶级Fable 5模型,在复杂工程开发、长文档深度分析、多步骤智能体自治、跨境多语言创作、海量数据挖掘五大高难度业务场景实现跨越式性能提升。
989 1
|
10天前
|
人工智能
Qwen3.8抢先体验!正式版即将发布并开源!
千问Qwen3.8即将开源,参数达2.4T,进化速度以“天”计,实力媲美Fable 5。预览版Qwen3.8-Max已上线阿里Token Plan等平台,限时优惠:日间Credits低至1折,夜间更优,个人/团队版月付仅35元起!
992 44
|
8天前
|
人工智能 自然语言处理 数据挖掘
最新版通义千问(Qwen3.8-Max-Preview)功能介绍
2026年,通义千问正式推出全新旗舰级大模型 **Qwen3.8-Max-Preview 预览版**,作为首款突破万亿参数规格的新一代基座模型,该模型总参数量达到**2.4万亿**,采用全新迭代的MoE混合专家架构,综合推理性能、长文本处理、多模态理解、复杂任务规划能力全面超越前代Qwen3.7-Max版本,整体实力跻身全球第一梯队,可对标海外顶级旗舰模型,是当前面向复杂工程开发、多智能体协同、超长文档解析、专业办公自动化场景的最优国产基座模型。
1004 0
|
7天前
|
自然语言处理 测试技术 API
通义千问Qwen3.8-Max-Preview全功能解析:2.4万亿参数旗舰模型深度使用指南
在大模型技术持续迭代的当下,通义千问推出的Qwen3.8-Max-Preview作为新一代旗舰预览版模型,凭借2.4万亿参数的超大规模、多模态融合能力与全场景适配特性,成为开发者与企业用户探索AI应用的核心工具。该模型采用稀疏混合专家(MoE)架构,是通义千问首个突破万亿参数的多模态模型,可同时处理文本、图像、视频与文档等多种数据形态,在全栈代码开发、复杂逻辑推理、长文档分析与多智能体协作等场景实现跨越式升级。本文将全面拆解Qwen3.8-Max-Preview的核心功能,详解API调用流程与配置方法,覆盖多场景实战技巧,帮助用户快速掌握这款旗舰模型的使用方法,充分释放其性能潜力。
488 1
|
10天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max 预览版全解析:2.4 万亿参数旗舰模型,Token Plan 限时优惠指南
Qwen3.8-Max-Preview是通义千问Qwen3系列旗舰MoE大模型,参数达2.4万亿,综合推理能力居行业第一梯队。支持思考/快速双模式,擅长大模型五大高难场景。现于阿里云百炼Token Plan、Qoder及QoderWork上线体验,个人版低至39元/月。在阿里云百炼官网:https://t.aliyun.com/U/fPVHqY 免费领取千万Tokens
690 1
Qwen3.8-Max 预览版全解析:2.4 万亿参数旗舰模型,Token Plan 限时优惠指南