一、查看元空间占用大小
jstat -gc 8
jstat -gccapacity 8
MC 为原空间大小,已用200M+,参数设置最大为256M
临时解决方案,配置调大,调整为512M。
二、分析元空间内存增加原因
- 下载JVM内存快照
jmap -dump:format=b,file=heap.hprof 8
- 使用OQL 日志来进行查询统计。
var packageClassSizeMap = {};
// 遍历统计以最后一个逗号做分割
heap.forEachClass(function (it) {
var packageName = it.name.substring(0, it.name.lastIndexOf('.'));
if (packageClassSizeMap[packageName] != null) {
packageClassSizeMap[packageName] = packageClassSizeMap[packageName] + 1;
} else {
packageClassSizeMap[packageName] = 1;
}
});
// 排序 因为Visual VM的查询有数量限制。
var sortPackageClassSizeMap = [];
map(sort(Object.keys(packageClassSizeMap), function (a, b) {
return packageClassSizeMap[b] - packageClassSizeMap[a]
}), function (it) {
sortPackageClassSizeMap.push({
package: it,
classSize: packageClassSizeMap[it]
})
});
sortPackageClassSizeMap;
效果:
发现 sun.reflect下存在 802个类,去包下查看实际类
存在大量类加载导致内存溢出,可在代码层面针对性解决处理
三、总结
1. 当时的临时方案是重启应用,元数据区清空,同时临时也可以放大元数据区大小。
2. 元数据区的泄漏排查思路:找到加载多的类,然后排查使用情况和可能的加载场景,一般在各种序列化反射场景。
3. 快速排查可使用我们的方案。使用 OQL 来完成。
4. 监控可以考虑加载类实例监控和元数据空间使用大小监控和对应报警。可以提前发现和处理。