几周前我曾提到,我被项目组分配去做了一些探究linux下内存管理机制的活儿。因为我们的产品遇到了一些与之相关的“诡异”问题。这些问题以及相关情况可以概括如下:
- 先介绍一下相关的背景。由于我们是3D软件,所以用户经常会有“导入/导出”各种geometry的需求。而一个存储这些数据的文件,可能含有不止一个geometry,而且每个geometry中也可能存在着成千上万个面片/多边形等各种基本元素。这些元素本身都不大,但数量很多。
- 第一次导入geometry时,会占据大量内存(比如说吧,有1.5G)以上;在不关闭软件而进行各种“清理”操作后,内存却基本不释放;接着再次导入相同的geometry时,内存也没有明显增加;然而如果再进行一次导入操作的话,内存又会被大量占用(约1G以上)。
- 将以上试验,换成先导入geometry1, 然后清理场景, 再导入geometry2,此时geometry2的内存占用量,要比单独首次导入geometry2时所占用的内存量要小。
- valgrind是一款在linux下经常使用检查各种内存管理问题的工具集合。我们用valgrind的memcheck组件进行过专门的内存泄露测试,并未发现明显的泄露情况。
- 我们的产品在mac平台上也有相应的版本。拿到mac os x上做实验,发现同样的代码,表现并不相同。其中每次清理场景后,都会有可观的内存(约600-800MB)被退回给操作系统(OS), 不过并不完全等于导入geometry前的内存量。
- 可以确定linux上的malloc函数用的是glibc的ptmalloc的实现。而mac上没有用到glibc,是它自己的实现。(具体信息待查)
- 我们的产品在为这些需求分配内存的时候,虽然经过“包装”,但主要是为了检查内存是否用尽从而及时提出警告。归根到底使用的还是标准的glibc的分配器(__libc_malloc(size_t))
以上的描述都是基于客观事实。而我探索的主要手段,就是根据这些事实搜索互联网(google/百度)。几天下来收获颇丰。下面总结一些收获。
-
类似的案例 :
- GLIBC内存分配机制引发的“内存泄露”
我们正在开发的类数据库系统有一个内存模块,出现了一个疑似”内存泄露”问题,现象如下:内存模块的内存释放以后没有归还操作系统,比如内存模块占用的内存为10GB,释放内存以后,通过TOP命令或者/proc/pid/status查看占用的内存有时仍然为10G,有时为5G,有时为3G, etc,内存释放的行为不确定。
- 有大量的相关提问在stackoverflow上可以被搜到。可自行搜索。比如这个 :
- GLIBC内存分配机制引发的“内存泄露”