如何定位Docker中Java应用Metaspace持续上涨但堆内存不变的触发类
Metaspace上涨问题定位方法
从提供的NMT数据可确认,Metaspace上涨完全由加载类数量从28562增长到51312导致,属于典型的类加载泄漏,可通过以下方法定位具体的泄漏类:
- 导出堆快照分析
执行jmap -dump:format=b,file=heap.hprof <进程ID>导出应用堆快照,使用MAT、JVisualVM等工具打开后,搜索java.lang.Class实例,按类加载器加载类的数量排序,即可定位到加载了大量异常类的类加载器,点击展开就能看到对应加载的全量类列表。绝大多数场景下这类泄漏都来自动态生成类的逻辑:比如CGlib动态代理、脚本引擎动态生成类、反射生成代理类、热部署框架重复加载类等。 - 打印类加载卸载日志
给应用添加JVM启动参数-XX:+TraceClassLoading -XX:+TraceClassUnloading,将日志输出到本地文件,统计日志中类的加载/卸载记录,只加载不卸载、重复加载次数极高的类就是泄漏来源。 - 用JDK自带工具直接查询类加载详情
执行jcmd <进程ID> GC.class_histogram,输出结果会列出当前JVM加载的所有类的统计信息,找到数量异常高的Class实例对应的类名即可。也可以执行jcmd <进程ID> VM.classloaders show-classes,直接输出每个类加载器加载的全量类列表,对比不同时间的输出就能快速找到异常增长的类。 - 结合业务逻辑排查
优先排查业务中使用动态类生成的逻辑:是否存在循环调用动态代理生成、每次执行脚本都新建脚本引擎不复用、自定义类加载器未正确释放、频繁序列化/反序列化生成ASM临时类的场景。
内容的提问来源于stack exchange,提问作者rookie
相关产品推荐
相关产品推荐

