读书人

有感于STL的内存储器管理 (转载)

发布时间: 2012-12-21 12:03:49 作者: rapoo

有感于STL的内存管理 (转载)

?

警告:本文是技术类文章,只适合码工们围观,非码工请跳过此坑


1. 背景

前些天在一个技术分享会上,某大牛说,STL使用了内存池,释放内存的时候,并不释放给OS,而是自己由留着用。

听到这些观点后,我就有些着急了,因为我以前一直是直接使用STL的一些工具类的,比如std::string、std::map、std::vector、std::list等等,从来都没有关注过内存的问题。

带着内存的问题,我花了两三天的时间去阅读STL的代码,并且写一些简单的程序进行测试;下面列举一些心得体会,但是却没有什么大的结论 -.-?



2. 容易误解的简单例子

我们以STL中的map为例,下面有一个使用map的简单例子,大部分人可以在30秒内写好。


void testmap()
{
? map<int, float> testmap;
? for (int i = 0; i < 1000000; i++) {
??? testmap[i] = (float)i;
? }
? testmap.clear();
}


为了在调用map::clear()之后查看进程的内存使用量,我们可以加几行代码让程序暂停一下。


void testmap()
{
? map<int, float> testmap;
? for (int i = 0; i < 1000000; i++) {
??? testmap[i] = (float)i;
? }
? testmap.clear();
? // 观察点
? int tmp; cout << "use ps to see my momory now, and enter int to continue:"; cin >> tmp;
}


编译运行上面的程序,你会看见这样的情况:ps显示进程的内存使用量为40MB多。这时,你会毫不犹豫地说,STL的map使用了内存池(memory pool)。

然后,我就跑去阅读libstdc++的STL的源代码,STL提供了很多种Allocator的实现,有基于内存池的,但是默认的std::allocator的实现是new_allocator,这个实现只是简单的对new和delete进行了简单的封装,并没有使用内存池。这样,怀疑的对象就转移到glibc的malloc函数了。malloc提供的两个函数来查看当前申请的内存的状态,分别是malloc_stats()和mallinfo(),它们都定义在<malloc.h>里。

为了弄清楚这个问题,我们对上面的例子进行如下的改造:


#include <malloc.h>
void testmap()
{
? malloc_stats();??? ??? // <======== 观察点1
? map<int, float> testmap;
? for (int i = 0; i < 1000000; i++) {
??? testmap[i] = (float)i;
? }
? malloc_stats();??? ??? // <======== 观察点2
? testmap.clear();
? malloc_stats();??? ??? // <======== 观察点3
}

这个例子的运行环境是这样的:

[dengmw@my ~]$ g++ -v
Reading specs from /usr/lib/gcc/x86_64-redhat-linux/3.4.6/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-java-awt=gtk --host=x86_64-redhat-linux
Thread model: posix
gcc version 3.4.6 20060404 (Red Hat 3.4.6-9)

程序的运行结果是这样的:

在观察点1:
*?????? system bytes???? =????????? 0
*?????? in use bytes???? =????????? 0
在观察点2:
*?????? system bytes???? =????????? 48144384
*?????? in use bytes???? =????????? 48005120
在观察点3:
*?????? system bytes???? =????????? 48140288??? <==== malloc cache the memory here
*?????? in use bytes???? =????????? 5120


很明显,尽管程序员显式地调用了map::clear(),但是malloc并没有把这些内存归还给OS,而是缓存起来了。所以说,这个例子的罪魁祸首并不是libstdc++的的STL,而是glibc的malloc。




3. 侯捷的《STL源码剖析》有点过时了
读书人网 >编程

热点推荐