尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Arthas classloader 命令完全指南:查看类加载器继承树、URL 与类加载关系

Arthas classloader 命令完全指南:查看类加载器继承树、URL 与类加载关系 Arthas classloader 命令完全指南查看类加载器继承树、URL 与类加载关系【免费下载链接】arthasAlibaba Java Diagnostic Tool Arthas/Alibaba Java诊断利器Arthas项目地址: https://gitcode.com/gh_mirrors/ar/arthasclassloader是 Arthas 提供的 JVM 类加载器诊断命令用于统计 JVM 中所有 ClassLoader 的信息、打印继承树、查看 URLClassLoader 的 urls并支持让指定 ClassLoader 执行getResources与loadClass操作。本文以 classloader 官方文档 为主线结合 ClassLoaderCommand.java 源码逐项剖析每个参数与场景的实现原理帮助你排查类加载冲突、ResourceNotFoundException、jar 包未生效等经典线上问题并深入掌握类与 jarURL的归属关系。命令概览与适用场景classloader命令将 JVM 中所有的 classloader 信息统计出来并可以展示继承树、urls 等。它可以分为三大类能力信息统计类按类加载器类型默认或实例-l统计加载数量打印继承树-t指定 ClassLoader 操作类查看某个 ClassLoader 的 urls-c/--classLoaderClass、用其查找 resource-r、用其加载类--loadURL 分析类统计每个 ClassLoader 实际使用/未使用的 URL--url-stat、统计指定 ClassLoader 中类与 jarURL的对应关系--url-classes。其中让指定的 classloader 去 getResources打印出所有查找到的 resources 的 url对于ResourceNotFoundException的排查非常有用——它可以直观地确认某个资源如META-INF/MANIFEST.MF、spring.factories、配置文件等到底被哪些 jar 提供、来自哪个 URL。参数说明命令支持以下参数与 classloader 文档 一致参数名称参数说明[l]按类加载实例进行统计[t]打印所有 ClassLoader 的继承树[a]列出所有 ClassLoader 加载的类请谨慎使用[c:]ClassLoader 的 hashcode[classLoaderClass:]指定执行表达式的 ClassLoader 的 class name[c: r:]用 ClassLoader 去查找 resource[c: load:]用 ClassLoader 去加载指定的类除文档表格所列参数外从 ClassLoaderCommand.java 的注解定义还可以看到以下补充参数其中-u/--url-stat在文档示例中已有体现参数名称参数说明源码注解-i, --include-reflection-classloader是否包含sun.reflect.DelegatingClassLoader等反射类加载器默认包含-u, --url-stat统计 ClassLoader 的 URL 使用情况-d, --details列出每个 URL/jar 加载的类名需与--url-classes配合-E, --regex--jar/--class使用正则匹配-n, --limit N详情模式下每个 URL/jar 最多展示 N 个类--jar kw按 jar 包名/URL 关键字过滤--class kw按类名/包名关键字过滤--url-classes参数说明参数名称参数说明--url-classes统计指定 ClassLoader 中已加载类与codeSource(URL/jar)的关系-d, --details详情模式列出每个 URL/jar 加载的类名建议配合-n/--limit控制输出量--jar kw按 jar 包名/URL 关键字过滤默认包含匹配--class kw按类名/包名关键字过滤默认包含匹配-E, --regex--jar/--class使用正则匹配默认关键字包含匹配-n, --limit N详情模式下每个 URL/jar 最多展示 N 个类100 默认需要特别注意的是-d/-E/-n/--jar/--class等选项必须与--url-classes搭配使用。从 process 方法的校验逻辑 可以看到若单独使用这些选项命令会直接报错Options -d/-E/-n/--jar/--class only work with --url-classes.而-n/--limit又要求与-d同时使用源码processUrlClasses中校验Option -n/--limit only works with --url-classes -d.且--limit必须大于 0。使用参考以下示例均基于官方文档整理附带源码层面的实现说明。示例中的3d4eac69、68b31f0a等均为演示环境下的 ClassLoader hashcode。按类加载类型查看统计信息直接执行classloader会按 ClassLoader 的**类型类名**聚合统计实例数量与加载类总数$ classloader name numberOfInstances loadedCountTotal com.taobao.arthas.agent.ArthasClassloader 1 2115 BootstrapClassLoader 1 1861 sun.reflect.DelegatingClassLoader 5 5 sun.misc.Launcher$AppClassLoader 1 4 sun.misc.Launcher$ExtClassLoader 1 1 Affect(row-cnt:5) cost in 3 ms.实现上对应源码 processClassLoaderStats遍历inst.getAllLoadedClasses()以classLoader.getClass().getName()Bootstrap 用固定名BootstrapClassLoader为 key 聚合成ClassLoaderStat含loadedCount与numberOfInstance两个计数器最后通过自定义ValueComparator按加载类总数从高到低排序输出。按类加载实例查看统计信息加-l参数按 ClassLoader实例逐条列出包含名称、加载数量、hashcode 与父加载器$ classloader -l name loadedCount hash parent BootstrapClassLoader 1861 null null com.taobao.arthas.agent.ArthasClassloader68b31f0a 2115 68b31f0a sun.misc.Launcher$ExtClassLoader66350f69 sun.misc.Launcher$AppClassLoader3d4eac69 4 3d4eac69 sun.misc.Launcher$ExtClassLoader66350f69 sun.misc.Launcher$ExtClassLoader66350f69 1 66350f69 null Affect(row-cnt:4) cost in 2 ms.从 getAllClassLoaderInfo 的实现可以看出遍历所有已加载类把类加载器归入MapClassLoader, ClassLoaderInfo同时沿着getParent()链把父加载器也补充进统计集合排序时把用户自定义的 ClassLoader 排在最前、sun.开头的放后面因为sun.reflect.DelegatingClassLoader实例太多。若不想看到反射类加载器可加-i之外的--include-reflection-classloader配合过滤器SunReflectionClassLoaderFilter该过滤器排除sun.reflect.DelegatingClassLoader与jdk.internal.reflect.DelegatingClassLoader——不过该参数默认即包含反射类加载器过滤是关闭状态。查看 ClassLoader 的继承树加-t参数以树状展示 ClassLoader 的父子继承结构$ classloader -t -BootstrapClassLoader -sun.misc.Launcher$ExtClassLoader66350f69 -com.taobao.arthas.agent.ArthasClassloader68b31f0a -sun.misc.Launcher$AppClassLoader3d4eac69 Affect(row-cnt:4) cost in 3 ms.树形结构由 processClassLoaderTree 构建先分离parent null的根节点再按父节点名称建立childMap递归buildTree挂接子节点。查看 URLClassLoader 实际的 urls用-c hashcode指定一个 ClassLoader打印其实际加载路径$ classloader -c 3d4eac69 file:/private/tmp/math-game.jar file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar Affect(row-cnt:9) cost in 3 ms.注意hashcode 是变化的需要先执行classloader或classloader -l查看当前 ClassLoader 信息提取对应 ClassLoader 的 hashcode 再传入。若目标不是URLClassLoader命令会输出not a URLClassLoader.见 processClassLoader。URL 获取逻辑封装在 ClassLoaderUtils.getUrls对URLClassLoader直接调用getURLs()对 JDK 9 的jdk.internal.loader.ClassLoaders$AppClassLoader等内置加载器则通过sun.misc.Unsafe反射获取其ucpURLClassPath字段再提取 URL——该兼容逻辑覆盖了 JDK 9~15字段位于ClassLoaders$AppClassLoader.ucp与 JDK 16~17字段位于父类BuiltinClassLoader.ucp的不同结构。对于只有唯一实例的 ClassLoader 可以通过 class name 指定使用起来更加方便$ classloader --classLoaderClass sun.misc.Launcher$AppClassLoader file:/private/tmp/math-game.jar file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar Affect(row-cnt:9) cost in 3 ms.--classLoaderClass通过 ClassLoaderUtils.getClassLoaderByClassName 按类名精确匹配。注意若匹配到多个同名 ClassLoader 实例命令会列出所有匹配项并报错Found more than one classloader by class name, please specify classloader with -c classloader hash此时需改用-c指定具体实例源码见 process 方法。使用 ClassLoader 去查找 resource用-c hashcode -r resource让指定 ClassLoader 执行getResources返回所有匹配该资源名的 URL$ classloader -c 3d4eac69 -r META-INF/MANIFEST.MF jar:file:/System/Library/Java/Extensions/MRJToolkit.jar!/META-INF/MANIFEST.MF jar:file:/private/tmp/math-game.jar!/META-INF/MANIFEST.MF jar:file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar!/META-INF/MANIFEST.MF也可以尝试查找类的 class 文件$ classloader -c 1b6d3586 -r java/lang/String.class jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar!/java/lang/String.class实现对应 processResources直接调用targetClassLoader.getResources(resource)遍历EnumerationURL输出全部结果资源读取失败时仅记录 warn 日志不会中断命令。这正是排查ResourceNotFoundException的利器可以直观看出某个资源在当前类加载器视角下能看到哪些 URL、是否一个都看不到。使用 ClassLoader 去加载类用-c hashcode --load 类名让指定 ClassLoader 尝试加载某个类并输出该类的完整元信息$ classloader -c 3d4eac69 --load demo.MathGame load class success. class-info demo.MathGame code-source /private/tmp/math-game.jar name demo.MathGame isInterface false isAnnotation false isEnum false isAnonymousClass false isArray false isLocalClass false isMemberClass false isPrimitive false isSynthetic false simple-name MathGame modifier public annotation interfaces super-class -java.lang.Object class-loader -sun.misc.Launcher$AppClassLoader3d4eac69 -sun.misc.Launcher$ExtClassLoader66350f69 classLoaderHash 3d4eac69demo.MathGame即仓库 math-game 示例应用 中的演示类。实现对应 processLoadClass调用targetClassLoader.loadClass(className)成功后通过ClassUtils.createClassInfo生成ClassDetailVO输出类的全部元信息加载失败则以非零码结束并输出load class error, class: ..., error: ...。该功能可用于验证某个 ClassLoader 到底能不能加载到某个类、加载到的是哪个 jar 里的版本是排查类冲突ClassCastException、NoClassDefFoundError的高效手段。统计 ClassLoader 实际使用 URL 和未使用的 URL加--url-stat短选项-u参数统计每个 ClassLoader 已使用与未使用的 URL$ classloader --url-stat com.taobao.arthas.agent.ArthasClassloader3c41660, hash:3c41660 Used URLs: file:/Users/admin/.arthas/lib/3.5.6/arthas/arthas-core.jar Unused URLs: sun.misc.Launcher$AppClassLoader75b84c92, hash:75b84c92 Used URLs: file:/Users/admin/code/java/arthas/math-game/target/math-game.jar file:/Users/admin/.arthas/lib/3.5.6/arthas/arthas-agent.jar Unused URLs: sun.misc.Launcher$ExtClassLoader7f31245a, hash:7f31245a Used URLs: file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/sunec.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/sunjce_provider.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/localedata.jar Unused URLs: file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/nashorn.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/cldrdata.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/legacy8ujsse.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/jfxrt.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/dnsns.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/openjsse.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/sunpkcs11.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/jaccess.jar file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/zipfs.jar实现对应 urlStats遍历inst.getAllLoadedClasses()从每个类的ProtectionDomain.getCodeSource().getLocation()收集实际被使用过的 URL再用ClassLoaderUtils.getUrls拿到该加载器的全部 URL差集即为 Unused URLs。::: warning 注意基于 JVM 目前已加载的所有类统计不代表Unused URLs可以从应用中删掉。因为可能将来需要从Unused URLs里加载类或者需要加载resources。 :::查看指定 ClassLoader 的类与 jar(URL) 的关系列表--url-classes用于统计指定 ClassLoader 中类来自哪个 jar(URL)以及每个 jar(URL) 加载了多少类$ classloader -c 3d4eac69 --url-classes sun.misc.Launcher$AppClassLoader3d4eac69, hash:3d4eac69 url loadedClassCount file:/private/tmp/math-game.jar 42 file:/Users/hengyunabc/.arthas/lib/arthas-agent.jar 15 Affect(row-cnt:2) cost in 3 ms.按 jar 包名关键字过滤并查看详情列出类名$ classloader -c 3d4eac69 --url-classes -d --jar math-game进一步按包名/关键字过滤同时会输出matchedClassCount便于统计$ classloader -c 3d4eac69 --url-classes --jar spring-core --class org.springframework实现对应 processUrlClasses核心逻辑为遍历inst.getAllLoadedClasses()仅保留clazz.getClassLoader() targetClassLoader的类源码以!判断跳过见 L514通过codeSourceLocation(clazz)取ProtectionDomain.getCodeSource().getLocation()确定每个类来自哪个 URL拿不到时为unknown常量UNKNOWN_CODE_SOURCE--jar过滤基于guessJarName从 URL 中解析出 jar 文件名兼容jar:file:/app.jar!/BOOT-INF/lib/spring-core-5.3.0.jar!/这类 Spring Boot 嵌套 jar 路径与完整 URL 做忽略大小写的包含匹配默认或正则匹配-E时--class过滤对类名做忽略大小写的包含/正则匹配若指定了类过滤最终只输出matchedClassCount 0的 URL 行-d详情模式下每个 URL 最多输出-n/--limit默认 100个类名超出部分以truncated标记截断结果按loadedClassCount有类过滤时按matchedClassCount降序、URL 字典序升序排序输出。这些匹配与解析行为有对应的单元测试佐证见 ClassLoaderCommandUrlClassesTest.java例如jar:file:/app.jar!/BOOT-INF/lib/spring-core-5.3.0.jar!/应解析出 jar 名spring-core-5.3.0.jarcontainsIgnoreCase(Spring-Core-5.3.0.jar, spring-core)应返回 true 等。该功能非常适合定位某个 ClassLoader 到底从哪些 jar 加载了哪些类、某类为何重复/缺失例如排查 Spring Boot fat jar 与外部部署目录中同名 jar 的类加载顺序问题。列出所有 ClassLoader 加载的类加-a参数可列出所有 ClassLoader 加载的类也可与-c组合只列出指定 ClassLoader 加载的类classloader -a classloader -a -c 327a647b实现对应 getAllClasses遍历inst.getAllLoadedClasses()按clazz.getClassLoader()归类classLoader null归入 Bootstrap按类名字典序排序每批 256 个类分页输出。请谨慎使用输出量可能非常巨大命令支持 CtrlC 中断源码通过ClassLoaderInterruptHandler设置isInterrupted标志配合分页回调在每批输出前检查中断见 processClassSet建议配合-c缩小范围。命令行为的整体调度逻辑从 process 方法 可以看到命令的分派顺序理解它有助于避免参数组合错误--url-stat优先执行不依赖-c--url-classes必须在指定了-c或--classLoaderClass时才能执行否则报错要求先指定 ClassLoader-c/--classLoaderClass解析目标 ClassLoader-c用Integer.toHexString(cl.hashCode())与传入 hashcode 匹配--classLoaderClass按类名匹配多实例时报错提示改用-c之后按优先级依次执行-a列类 指定 ClassLoader -r查资源 指定 ClassLoader --load加载类 仅指定 ClassLoader打印 urls-l或-t实例统计/继承树 默认按类型统计。所有结果通过 ClassLoaderModel 统一承载包含 classSet、resources、loadClass、urls、classLoaders、classLoaderStats、urlStats、urlClassStats 等字段最终由 Shell 层渲染输出。总结与相关资源classloader命令是 Arthas 类加载器诊断的入口级工具从宏观的类型统计、实例列表、继承树到微观的单实例 URL、资源查找、类加载验证再到 URL 级的使用率与类-jar 归属分析覆盖了类加载问题排查的完整链路。使用时牢记两点hashcode 每次运行都会变化需先查询再引用-a、-d等输出可能巨大善用-c限定范围、用-n/--limit限制输出量、必要时 CtrlC 中断。可进一步阅读的仓库资料命令实现ClassLoaderCommand.javaURL 获取与兼容逻辑ClassLoaderUtils.java结果模型ClassLoaderModel.java单元测试ClassLoaderCommandUrlClassesTest.java英文版文档classloader (EN)关联命令classloader-metaspace 命令查看 ClassLoader 的 Metaspace 使用情况【免费下载链接】arthasAlibaba Java Diagnostic Tool Arthas/Alibaba Java诊断利器Arthas项目地址: https://gitcode.com/gh_mirrors/ar/arthas创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表