我们知道C++程序中分配和释放内存的代码片段可以说不计其数,我们经常会直接或者间接的用到malloc()
和free()
来分配和释放内存,提供这套机制的默认程序库是ptmalloc,ptmalloc是一个内存分配器的标准实现。
在ptmalloc的malloc/free机制中,有一个延迟释放的情况,概括来讲就是我们使用free()
释放malloc()
申请的内存后,这部分内存可能不会立即归还给操作系统,而是在满足某个条件之后才会归还,这种延迟释放的情况在因为频繁分配和释放小块内存而产生大量内存碎片时尤其明显。
在出现这种延迟释放的情况时就可能会导致程序(进程)占用的内存资源居高不下,很显然这是一个需要解决的问题,malloc_trim()
就是一种解决方案,但是这种解决方案可能不是很好,好像有点亡羊补牢的意思了,但是我们姑且也来讨论一下,因为毕竟还是很实用的。
使用malloc_trim()
可以将已经使用free()
释放但是未归还给操作系统的内存立即归还给操作系统,具体介绍可以man malloc_trim
查看,我们来看一个示例
// main.cpp
#include <malloc.h>
#include <vector>
int main()
{
std::vector<void *> vecPtr;
for (int i = 0; i < 1024 * 1024; ++i)
{
vecPtr.push_back(malloc(16));
}
for (const auto &ptr : vecPtr)
{
free(ptr);
}
getchar(); // 等待输入,为了方便查看此时内存占用情况
malloc_trim(0); // 归还所有可归还的内存资源
getchar(); // 等待输入,为了方便查看此时内存占用情况
return 0;
}
在上面这个示例程序中会频繁的分配和释放小块内存,我们执行命令g++ -g ./main.cpp -o MallocTrimDemo
构建一下程序
启动这个程序,然后使用命令ps -ef | grep ./MallocTrimDemo
查到进程号
然后使用命令top -p <PID>
查看调用malloc_trim()
之前的内存资源占用情况
然后触发一下malloc_trim()
看调用malloc_trim()
之后的内存资源占用情况(可别问咋触发malloc_trim()
,看一下前面示例代码的逻辑就知道了)
可以看到内存资源占用的变化很明显,这就是malloc_trim()
的效果。
这里需要提醒一下的是,如果在测试的时候不会出现延迟释放的情况(即在调用malloc_trim()
的前后内存资源占用基本不变化),可以调整申请的内存块大小以及申请的内存块的数量重新测试。
现在我们知道了存在这么个情况,所以如果发现某个程序(进程)占用的内存资源居高不下,远超实际应该占用的内存,而又能确定未发生内存泄漏的情况时,就可以检查一下是不是这种延迟释放的原因了。
前面说使用malloc_trim()
处理可能不是一个很好的解决方案,那还有什么解决方案呢,其实还挺多的,比如用tcmalloc或者jemalloc而不是默认的ptmalloc(当然并不意味着ptmalloc不够好,如果不好又怎么会是标准实现呢,ptmalloc基本上所有场景都可以兼容,只是某些场景下会有更适合使用的程序库),比如用内存池,可以根据具体情况选择解决方案。
如果这篇文章对你有帮助,别忘了关注我啊,可能我还会写出更多对你有帮助的文章
因篇幅问题不能全部显示,请点此查看更多更全内容