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

如何获取Metaspace使用直方图以排查元空间内存溢出问题?

解决方法

一、使用JDK原生工具jcmd统计Jar包级元空间占用

步骤1:获取目标进程ID

执行以下命令列出Java进程:

jps

或直接用jcmd查看所有进程:

jcmd

步骤2:导出类的元空间统计数据

替换<pid>为你的进程ID,执行命令导出详细类元数据:

jcmd <pid> GC.class_stats > class_stats.txt

该输出包含每个类的元空间占用、类加载器、所属Jar包路径等核心信息。

步骤3:按Jar包汇总占用数据

创建jar_metaspace_stats.awk脚本文件:

/^[0-9]+/ {
    jar_path = $NF
    class_size = $5
    total[jar_path] += class_size
}
END {
    for (jar in total) {
        printf "%.2f MB\t%s\n", total[jar]/1024/1024, jar
    }
}

执行脚本并按占用从大到小排序:

awk -f jar_metaspace_stats.awk class_stats.txt | sort -nr

输出示例:

128.50 MB	/path/to/spring-core-5.3.20.jar
96.20 MB	/path/to/hibernate-core-5.6.10.Final.jar
...

二、结合堆转储与jhat分析元空间占用

步骤1:生成堆转储文件

替换<pid>为进程ID,生成包含元空间信息的堆转储:

jmap -dump:live,format=b,file=heap_dump.hprof <pid>

步骤2:用jhat查询汇总数据

启动jhat服务:

jhat heap_dump.hprof

浏览器访问http://localhost:7000,进入OQL Console,执行以下查询按Jar包汇总:

SELECT 
    cls.source AS jar_path,
    sum(cls.instanceKlassSize)/1024/1024 AS total_mb
FROM java.lang.Class cls 
WHERE cls.source IS NOT NULL
GROUP BY cls.source 
ORDER BY total_mb DESC

若需按包名统计,可修改为:

SELECT 
    substring(cls.name, 0, indexOf(cls.name, '.')) AS package_name,
    sum(cls.instanceKlassSize)/1024/1024 AS total_mb
FROM java.lang.Class cls 
GROUP BY package_name 
ORDER BY total_mb DESC

三、Spring代理类的专项统计

由于应用大量使用@Inject会生成CGLIB/JDK代理类(类名含$$EnhancerBySpringCGLIB$$或$Proxy),这类类的source字段通常为空,可单独统计:

awk '/\$\$EnhancerBySpringCGLIB\$\$|Proxy$/ {sum += $5} END {print "Proxy classes total: " sum/1024/1024 " MB"}' class_stats.txt

额外建议

  1. 服务器自身已占用300MB元空间,剩余212MB不足以承载应用类+代理类,结合统计结果可精简未使用的Jar包,降低类总量。
  2. 检查Spring代理逻辑,确认是否存在对无需代理的类过度使用注解的情况,减少动态生成类的数量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:08:13