gnu c++的allocator

1.gnu c++中的allocator类型

  • array_allocator
  • bitmap_allocator(和mfc中的bitmap无关)
  • malloc_allocator
  • mt_allocator(多线程)
  • new_allocator
  • extptr_allocator
  • debug_allocator
  • pool_allocator
  • throw_allocator
    其中new_allocator与pool_allocator在STL内存分配allocator介绍过。
    在这里插入图片描述
    在这里插入图片描述

class allocator只拥有typedef constructor 和rebind等成员,它继承自一个high-speed extension allocators。因此所有的分配和释放都取决于base class,而这个base class也许是终端用户无法触碰和操作的。因为有的是private继承的。而且主要用于分配内存的函数都在基类中,如pool_allocator的_M_refill。

2.malloc_allocator

// NB: __n is permitted to be 0.  The C++ standard says nothing
// about what the return value is when __n == 0.
pointer
allocate(size_type __n, const void* = 0)
{
	if (__n > this->max_size())
  		std::__throw_bad_alloc();
  		
	pointer __ret = static_cast<_Tp*>(std::malloc(__n * sizeof(_Tp)));
	if (!__ret)
  		std::__throw_bad_alloc();
	return __ret;
}

// __p is not permitted to be a null pointer.
void
deallocate(pointer __p, size_type)
{ std::free(static_cast<void*>(__p)); }

malloc_allocatorallocate直接调用的mallocdeallocate直接调用free

3.array_allocator

在这里插入图片描述
_M_array的类型是array_type*array_type* _M_array;
array_type类型与_Array相同;typedef _Array array_type;
_Array是传入的参数,默认为std::tr1::array<_Tp, 1>

3.1 构造函数

array_allocator(array_type* __array = 0) _GLIBCXX_USE_NOEXCEPT 
      : _M_array(__array), _M_used(size_type()) { }

_M_array使用__array初始化,__array默认值为0,用户如果不写就是0,如果写就是用户传进来的地址,这个地址在allocate中有用到。

3.2 使用形式

在这里插入图片描述

int my[65536];
array_allocator<int, array<int, 65536>> myalloc(&my);//template<typename _Tp, typename _Array = std::tr1::array<_Tp, 1> >, 前面的_Tp与后面array中的_Tp要一致。

在这里插入图片描述
在构造函数中需要传入一个指针,这个指针可以指向静态分配的数组,也可以指向动态分配的数组,所以说内存分配不是在array_allocator中进行的,array_allocator只是对分配好的内存进行管理。

3.3 deallocate

array_allocator中没有写deallocate,但是他的父类中有,父类中的deallocate如下:

void
deallocate(pointer, size_type)
{ 
// Does nothing.
}

可以看到,deallocate只是保留了一个接口,但内部什么也没有做,因为内存不是在array_allocator分配的,所以它也不能free。

3.4 array_allocator

pointer
allocate(size_type __n, const void* = 0)
{
	if (_M_array == 0 || _M_used + __n > _M_array->size())//如果内存不够用,抛出异常
		std::__throw_bad_alloc();
	pointer __ret = _M_array->begin() + _M_used;//得到返回给用户的指针
	_M_used += __n;//调整指针位置
	return __ret;
}

可以看出它只是对已经分配好的一块进行管理,每次用户要内存就在分好的内存中给用户一块,同时将移动当前使用量指针_M_used

4.bitmap_allocator

视频讲解连接:bitmap_allocator上

4.1 allocate

pointer 
allocate(size_type __n)
{
	if (__n > this->max_size())
		std::__throw_bad_alloc();

	if (__builtin_expect(__n == 1, true))//如果数量为1个,则调用_M_allocate_single_object()
		return this->_M_allocate_single_object();
	else	//如果申请的数量大于1个,则直接调用operator new
	{ 
	    const size_type __b = __n * sizeof(value_type);
	    return reinterpret_cast<pointer>(::operator new(__b));
	}
}

4.2 deallocate

void 
deallocate(pointer __p, size_type __n) throw()
{
	if (__builtin_expect(__p != 0, true))
	{
		if (__builtin_expect(__n == 1, true))//如果数量为1,则调用_M_deallocate_single_object()释放
			this->_M_deallocate_single_object(__p);
	    else
			::operator delete(__p);//数量大于1使用operator delete释放
	}
}

4.3 内部结构

4.3.1 分配

在这里插入图片描述
首先是64个blocks,每一个对象占用1个block,64个blocks加上bitmap[1]和bitmap[0]再加上use count形成一个super block。即super block = 64*block + bitmap[1] + bitmap[0];
use count表示64个block已经用了几个,如果某一个block被使用了,那么bitmap[1]和bitmap[0]相应bit的数字变为0,bitmap[1]和bitmap[0]均为unsigned int,所以两个加起来共有64比特,也就可以表示64个block的使用情况。
在最前面还有一个数字,表示super block的大小,上图中的大小为:4(use count)+4 * 2(bitmap)+64*8(单个对象大小)=524字节。单个对象的大小只能是8的倍数。

多个super block是通过__mini_vector管理的,__mini_vector是一个vector,但不是标准库的vector,而是自己写的一个vector,但它与标准库中的vector拥有同样的特性——两倍增长。也就是说,如果64个block用光了,下次会分配128个block。
__mini_vector有3个用来管理内存的成员变量。

  private:
	pointer _M_start;
	pointer _M_finish;
	pointer _M_end_of_storage;

当64个block用光时,会再申请128个,然后bitmap变为4个。和vector的成长一样,会申请另一块内存然后将现在的搬过去:
在这里插入图片描述
当128个用光的时候就会再去分配256个:
在这里插入图片描述
每次都这样成长两倍,2的幂次方级别地成长。

每个entry代表一种value_type:意思是说,即使两种类的对象拥有相同的大小,但是由于其value_type不同,不能共用一个super block。

4.3.2 回收

在这里插入图片描述
第一个super block全部回收,会有另外一个vector中的元素(free_list)指向回收的区块,下次再分配super block时,数量会减半,也就是会分配128个。
Q:如果第一个super block没有被全部回收,还剩2个,后面的super block也还有空余,那么下次再分配2个的时候是从第一个super block分配还是从后面的super block分配?
A:从后面的区块分配。
Q:那后面的被用光了怎么办呢?是重新分配还是使用第一个super block空闲的2块呢?
A:使用super block中空闲的两个。
在这里插入图片描述
不断地回收,然后管理回收区域的vector就不断增长,但是它只能包含64个entry,当第65个再被回收时,如果新加入的第65个比前64个中最大的还要大,那么直接删除第65个,不将其添加至free_list;如果加入的第65个比前64个中最大的小,那么就将前64个中最大的删除,然后将第65个添加至free_list。
在这里插入图片描述
Q:假设现在3个super block全部被回收了,也就是上图中的__S_mem_blocks为空,而__S_free_list有3个super block,那么下次再分配的时候是分配第四个super block还是从回收的3个中拿一个出来?
A:从回收的3个中拿一个出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值