STL源码剖析---------SGI空间配置器

书中说到:delete应该是调用对象的析构函数,然后释放内存;,destory也是调用对象的析构函数,vector的析构函数就是先调用了destory,调用对象类型的析构函数,然后调用deallocate释放内存;书上的解释是只是将delete的操作分开了;先是调用析构函数,然后释放内存;记录一下。

STL allocator将new和delete进行了分开操作:

内存分配操作由alloc::allocate() 进行,内存释放操作由alloc::deallocate() 负责;

对象构造操作由::construct() 负责,对象析构操作由::destory() 复杂;

内存的配置与释放:

考虑到小型区块所可能造成的内存破碎问题,SGI设计了双层级配置器,当配置区块大于128bytes时,则调用第一级配置器,此配置器使用C的malloc和free来完成内存的配置和释放;

这里引用以下别人的关于malloc/free与new/delete的区别与相同之处:

相同:都可用于申请动态内存和释放内存

不同:malloc与free是C++/C 语言的标准库函数,new/delete 是C++的运算符,可以重载。对于非内部数据的对象(c++)而言,光用maloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数, 对象消亡之前要自动执行析构函数。由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加malloc/free;

用法上,malloc需要指定分配内存的大小,而new却不需要(内部自己操作),并且malloc返回的是void *的指针,需要强制转换,但是new是类型是一样的,且当分配失败时,malloc返回NULL,而new返回bad_alloc 异常,需要捕捉,既没有返回;

new还可以初始化对象,但是malloc只管分配,对象的值是无意义的;

既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。


上面说到,当分配区块超过128bytes时,视为足够大,便调用第一级配置器malloc/free,当分配区块小于128bytes时,视之为“过小”,为了降低额外负担,便采用复杂得内存池整理,而不使用第一级配置器;

注:这里的额外负担,意思是说,因为当分配的区块太小,则容易造成内存碎片,这里的额外负担我理解的是说,当你一个程序申请了很多小内存,则释放之后,就可能会产生很多内存碎片,当这个进程在需要大点的内存的时候,就很难获得,这时候可能会进行频繁的内存与磁盘的换进换出,开销会很大,

因此,为了降低额外负担,SGI采用了内存池整理方式,而不在求助于第一级配置器;

第一级配置器没啥好说的,就是对malloc和free的封装;

下面着重说一下第二级配置器

当区块小于128bytes时,每次通过malloc配置一大块内存,并维护对应之自由链表,为了内存对齐,这里维护了8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,每次对申请的小内存上调至8的倍数,通过自由链表可以很方便的管理各种尺寸的内存,比如回收小内存,直接将其插入到链表的开头即可,因此是常数时间,这里找合适的节点,其实是通过首次适配来找的,因为这里也不需要进行合并,所以并没有将节点根据地址顺序放入;

由于每一个节点都需要指向下一个节点,为了维护链表,我们需要一个数据结构,用来存储下一个节点,为了不造成额外负担,这里用了一种c++的数据类型

union obj{
    union obj* free_list_link;
    char client_data[1];
}

这里维护了内存池剩余空间的大小

static char *start_free ;
static char *end_free ;

这里如果没有找到对应大小的节点时,说明链表中没有相对应得空闲块,这样得话,就会调用refill函数,将内存池剩余得空间bytes_left=end_free-start_free;配置到链表中,这里当剩余空间过大的时候,就配置20个需要尺寸的块,将首块分配出去,然后剩下的19块就插入到对应链表的节点处,

                        

如果剩余空间不能分配20个了,那就把剩下的都分配了,如果没剩余空间了,那就调用malloc,分配一块内存给内存池,进行重新分配;如果堆中空间也不足了,那就调用异常来解决


总结一下,这里通过内存池技术,就可以很好的分配小内存,这样就会避免小内存导致的外部碎片,因为它将统一的分配小块内存,这样每个进程,都能很好的利用所分配的内存空间,尽量可以获得大的内存块了。从而空间利用率显著提升,这里也是和非连续的物理地址空间时有关系的。使得每个进程并不是需要一块连续的内存空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值