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箇中拿一個出來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章