__gnu_cxx::__mt_alloc 是stl 拓展库的支持多线程应用的内存分配器。
__gnu_cxx::__mt_alloc是一个固定大小(2的幂)内存的分配器,最初是为多线程应用程序(以下简称为MT程序)设计的。经过多年的改进,现在它在单线程应用程序(以下简称为ST程序)里也有出色的表现了。
template
这个类表示是否支持线程,然后对多线程(bool==true)和单线程(bool==false)情况进行显式特化。可以用定制的参数来替代这个类。
对于policy类,至少有2种不同的风格,每种都可以和上面不同的内存池参数单独搭配:
策略一:
__common_pool_policy,实现了一个通用内存池,即使分配的对象类型不同,比如char和long,也使用同一个的内存池。这是默认的策略。
template
struct __common_pool_policy
template
struct __per_type_pool_policy
策略二:
__per_type_pool_policy,对每个对象类型都实现了一个单独的内存池,于是char和long会使用不同的内存池。这样可以对某些类型进行单独调整。
实际的内存分配器:
template
class __mt_alloc : public __mt_alloc_base<_Tp>, _Poolp
这个类有标准库要求的接口,比如allocate和deallocate函数等。
有些配置参数可以修改,或调整。有一个嵌套类:包含了所有可调的参数,即:
struct __pool_base::_Tune
代码:默认配置(8字节对齐,128字节以上的内存直接用new分配,可分配的最小的内存块大小8字节,每次从os申请的内存块的大小为4080字节,可支持的最多的线程数是4096,单线程能保存的空闲块的百分比为10%,是否直接使用new和delete 根据 是否设置 getenv("GLIBCXX_FORCE_NEW")
// Variables used to configure the behavior of the allocator,
// assigned and explained in detail below.
struct _Tune
{
// Compile time constants for the default _Tune values.
enum { _S_align = 8 };
enum { _S_max_bytes = 128 };
enum { _S_min_bin = 8 };
enum { _S_chunk_size = 4096 - 4 * sizeof(void*) };
enum { _S_max_threads = 4096 };
enum { _S_freelist_headroom = 10 };
特性:
1)字节对齐
2)多少字节以上的内存直接用new分配
3)可分配的最小的内存块大小
4)每次从OS申请的内存块的大小
5)可支持的最多线程数目
6)单个线程能保存的空闲块的百分比(超过的空闲块会归还给全局空闲链表)
7)是否直接使用new和delete
可以通过接口来设置和获取这个参数
const _Tune&
_M_get_options() const
{ return _M_options; }
void
_M_set_options(_Tune __t)
{
if (!_M_init)
_M_options = __t;
}
对这些参数的调整必须在任何内存分配动作之前,即内存分配器初始化的时候,比如:
#include
struct pod
{
int i;
int j;
};
int main()
{
typedef pod value_type;
typedef __gnu_cxx::__mt_alloc allocator_type;
typedef __gnu_cxx::__pool_base::_Tune tune_type;
tune_type t_default;
tune_type t_opt(16, 5120, 32, 5120, 20, 10, false);//16字节对齐,5120字节以上的内存直接用new分配,可分配的最小的内存块大小32字节,每次从os申请的内存块的大小为5120字节,可支持的最多的线程数是20,单线程能保存的空闲块的百分比为10%
tune_type t_single(16, 5120, 32, 5120, 1, 10, false);
tune_type t;
t = allocator_type::_M_get_options();
allocator_type::_M_set_options(t_opt);
t = allocator_type::_M_get_options();
allocator_type a;
allocator_type::pointer p1 = a.allocate(128);
allocator_type::pointer p2 = a.allocate(5128);
a.deallocate(p1, 128);
a.deallocate(p2, 5128);
return 0;
}
首次调用allocate()时,也会调用_S_init()函数。MT程序里,为了保证只被调用一次,我们使用了__gthread_once(参数是_S_once_mt和_S_init)函数;在