Linux下对象销毁后驻留集大小(RSS)未下降及强制释放内存问询
问题原理与解决方案
两个测试的行为差异原因
Linux 系统下 glibc 的默认内存分配器采用两种分配路径区分处理不同大小的内存申请:
- 小于默认
MMAP_THRESHOLD(通常为 128KB)的内存申请,会通过brk系统调用从进程堆区分配。这部分内存被应用释放后,不会直接归还给操作系统,而是由 glibc 分配器缓存在进程的内存池中,供后续同大小范围的内存申请复用,减少系统调用开销。你的第一个测试中MyApplication内部分配的都是小于该阈值的小块内存,因此释放后内存被分配器截留,RSS 不会下降。 - 大于等于
MMAP_THRESHOLD的内存申请,默认通过mmap系统调用分配独立的匿名内存页。这部分内存被释放时会直接调用munmap解除页映射,内存会立刻归还给操作系统。你的第二个测试中 500MB 的大内存申请走的是 mmap 分配路径,因此shared_ptr销毁触发释放后,RSS 会立刻下降。
强制进程返还空闲内存给系统的方法
你可以通过以下几种方式实现内存强制回收:
- 调用 glibc 专用回收接口
调用malloc_trim(0)函数,该接口会主动扫描进程堆区的空闲内存,将堆顶连续的未使用内存通过收缩堆边界归还给操作系统,同时也会回收所有闲置的 mmap 内存块。参数传 0 表示尽可能多归还空闲内存,不要保留堆顶缓冲。
需要注意:如果堆区中间存在仍被使用的小块内存,导致空闲内存碎片化不连续,那么中间的空闲页无法被归还,只有堆顶连续的空闲内存会被回收。 - 调整内存分配阈值
调用mallopt(M_MMAP_THRESHOLD, 阈值大小)调低MMAP_THRESHOLD,让更多内存申请走 mmap 路径,释放时自动归还系统。比如设置为 4KB 时,所有大于 4KB 的内存申请都会走 mmap 分配。但该方案会带来明显的性能损耗,因为 mmap/munmap 的系统调用开销远高于 brk 分配+缓存复用的方案,不适合频繁申请释放小块内存的场景。 - 直接使用系统调用管理内存
对生命周期明确的大内存块,直接调用mmap/munmap自行管理,完全绕过 glibc 分配器的缓存逻辑。
内容的提问来源于stack exchange,提问作者Ziqi Liu
相关产品推荐
相关产品推荐

