支持多线程的内存分配器__gnu_cxx::__mt_alloc

__gnu_cxx::__mt_alloc 是stl 拓展库的支持多线程应用的内存分配器。

1、__mt_alloc组成部分

 __gnu_cxx::__mt_alloc是一个固定大小(2的幂)内存的分配器,最初是为多线程应用程序(以下简称为MT程序)设计的。经过多年的改进,现在它在单线程应用程序(以下简称为ST程序)里也有出色的表现了。

 (1)线程支持参数

template  class __pool

这个类表示是否支持线程,然后对多线程(bool==true)和单线程(bool==false)情况进行显式特化。可以用定制的参数来替代这个类。

(2)把内存池关联到通用或专用方案的policy

对于policy类,至少有2种不同的风格,每种都可以和上面不同的内存池参数单独搭配:

策略一:

__common_pool_policy,实现了一个通用内存池,即使分配的对象类型不同,比如charlong,也使用同一个的内存池。这是默认的策略。

template
    struct __common_pool_policy

    template
    struct __per_type_pool_policy

策略二:

__per_type_pool_policy,对每个对象类型都实现了一个单独的内存池,于是charlong会使用不同的内存池。这样可以对某些类型进行单独调整。

(3)实际的内存分配器类

实际的内存分配器:

template
    class __mt_alloc : public __mt_alloc_base<_Tp>,  _Poolp

这个类有标准库要求的接口,比如allocatedeallocate函数等。 

 (4)描述内存池特征的参数

有些配置参数可以修改,或调整。有一个嵌套类:包含了所有可调的参数,即:

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)是否直接使用newdelete


可以通过接口来设置和获取这个参数

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;
}

2、基类配置初始化

(1)基类配置

首次调用allocate()时,也会调用_S_init()函数。MT程序里,为了保证只被调用一次,我们使用了__gthread_once(参数是_S_once_mt_S_init)函数;在

你可能感兴趣的:(支持多线程的内存分配器__gnu_cxx::__mt_alloc)