unknown是什么牌子(内存Unknown是杂牌吗)

2024-12-2806:05:45综合资讯0

阿里开发者 叔耀

阿里妹导读

本文详细记录了一次由glibc导致的堆外内存的排查过程。

问题现象

团队的核心应用每次发布后,内存会逐渐占用,不进行重启或重新部署就会导致整体内存占用率超过预期。

探索原因一

初探时,我们曾随机选择一台机器进行内存转储,查看是否为堆内存使用率过高所致。发现一个占比达到18.8%的对象。

暂时性修复方案

1. 更换当前加载的俄罗斯(RU)国际地址库为以色列(IL)的小型地址库。

2. 对于仍在使用的业务场景,添加打点日志,确认是否仍有业务在使用该服务。若无人使用,则直接下架。实际发现仍有业务在使用。

发布后的观察

发布后短时间内内存增长属正常现象,需持续观察。发布第二天再次转储同一台机器的内存,发现占比从18.8%降低到4.07%,降低了14%,效果显著。

探索原因二

发布后的内存使用率又飙升至86%,这让我们再次陷入困惑,必须深入探究为何内存会占用如此之大。

查看进程与堆内使用情况

java进程的内存使用率为84.9%,RES为6.8G。当前机器配置为4Core 8G,堆最大5G,堆使用不足3G。使用arthas等工具查看当前内存使用情况,发现堆内加非堆内存的使用量远超RES。开始怀疑是“堆外内存”。

NMT与rssAnalyzer工具应用

通过NMT显示的是“committed”内存,而非“resident”内存。我们虽未使用该功能,但类似功能的rssAnalyzer工具可通过oss在预发/线上下载使用。通过NMT查看,基本确认了是堆外内存。

堆外内存分析

在32位系统中,堆外内存申请多为1M,而在64位系统中,多为64M。为了定位具体的泄,推荐使用pmap或strace等工具进行深入分析。strace可用于追踪系统的内存申请与释放操作,如brk、mmap、munmap等。glibc的内存分配机制也是关键因素。glibc默认的内存分配器在多线程环境下可能存在内存分配与释放的不当操作,导致内存。

哪里在?

经过进一步分析,我们发现是通过Java的java.util.zip.Inflater流申请的JNI内存导致了。特别是在使用InflaterInputStream(InputStream in)构造对象时,若usesDefaultInflater设置为true,在流关闭时可能会尝试归还但并不一定能真正归还给操作系统,从而造成内存。此问题在二方包扫描中发现,例如pandora的ZipInflaterInputStream曾经存在此问题,但幸运的是在2年前已修复。确保使用的pandora版本至少为2.1.17以上,以避免此问题。

问题解决与总结

为了解决此问题,我们需与jdk团队的同学沟通,确认使用jemalloc作为内存分配器的合适版本。幸运的是,我们的基础镜像做了统一升级,相关同学已通过dockerfile进行了from的版本升级。