__mt_alloc源碼分析(3)

struct __common_pool

__common_pool__common_pool_base的基類,它作用就是定義pool_type和實現_S_get_pool函數。

 

382    template<template <bool> class _PoolTp, bool _Thread>

383      struct __common_pool

 

__common_pool的原型,模板參數_PoolTp是實際的內存池類,_Thread表示是否支持多線程。

 

384      {

385        typedef _PoolTp<_Thread>      pool_type;

386       

387        static pool_type&

388        _S_get_pool()

389        {

390     static pool_type _S_pool;

391     return _S_pool;

 

前面說過,common pool是一種內存池策略,即所有的對象類型使用同一個內存池,那麼這個內存池就是上面的_S_pool

 

392        }

393      };

 

寫到這裏,我突然很有興趣看看per type pool的架構和實現,是否也是類似的。前面已經對比過__per_type_pool_policy__common_pool_policy,那麼我們就從__per_type_pool_base開始看起吧。

 

struct __per_type_pool_basestruct __per_type_pool

__per_type_pool_base的代碼位於490543之間,和__common_pool_base的代碼幾乎一模一樣,除了名字不同和多了一個模板參數_Tp,所以我不想浪費篇幅陳列這些重複的代碼。相比之下,__per_type_pool的代碼就有趣得多,所以這個小節的重點是__per_type_pool

 

464    template<typename _Tp, template <bool> class _PoolTp, bool _Thread>

465      struct __per_type_pool

466      {

467        typedef _Tp           value_type;

468        typedef _PoolTp<_Thread>      pool_type;

 

首先,__per_type_pool__common_pool多了一個value_type,這是分配對象的類型。其次,__per_type_pool針對每種_Tp(也就是value_type)都會實例化成不同的類型,所以下面的靜態函數_S_get_pool和返回的靜態變量_S_pool對於每種_Tp都是不同的。這就實現了對_Tp類型的定製內存池。

 

470        static pool_type&

471        _S_get_pool()

472        {

473     // Sane defaults for the _PoolTp.

474     typedef typename pool_type::_Block_record _Block_record;

 

_Block_record本來應該在後面研究的,不過這裏可以先介紹一下。它實際上就是一個內存塊的“頭信息”,典型的唯一成員就是指向下一個塊的指針next

 

475     const static size_t __a = (__alignof__(_Tp) >= sizeof(_Block_record)

476                    ? __alignof__(_Tp) : sizeof(_Block_record));

 

關鍵字__alignof__用於查看某個類型在具體平臺上的對齊字節數,它的語法和sizeof一樣,詳細信息可以參考http://www.delorie.com/gnu/docs/gcc/gcc_61.html。在流行的32位機器平臺上,sizeof(_Block_record)值爲4__alignof__(_Tp)的值可能爲1248__a等於較大者(48)。

考慮一下,每個空閒內存塊由2部分組成,頭信息(_Block_record)和數據(_Tp),由於在mt allocator裏,頭信息不能被數據覆蓋(因爲多線程下還要記錄線程id,並且是重用了_Block_record中的next指針),所以數據區究竟在整個塊的什麼位置,是編譯器參考了_Tp類型的對齊規則之後決定的事情,所以這段代碼就是爲了準確的得到這個偏移量。

 

478     typedef typename __pool_base::_Tune _Tune;

479     static _Tune _S_tune(__a, sizeof(_Tp) * 64,

480                  sizeof(_Tp) * 2 >= __a ? sizeof(_Tp) * 2 : __a,

481                  sizeof(_Tp) * size_t(_Tune::_S_chunk_size),

482                  _Tune::_S_max_threads,

483                  _Tune::_S_freelist_headroom,

484                  getenv("GLIBCXX_FORCE_NEW") ? true : false);

 

__pool_base::_Tune是內存池控制參數的類型,裏面包含了7個參數,通過構造函數一一賦值,每個參數的意義在前面已經做過介紹(參考mt allocator原理介紹)。靜態變量_S_tune最後會根據_Tp的類型合適的初始化它的每個參數值。

 

485     static pool_type _S_pool(_S_tune);

 

用定製的控制參數_S_tune構造定製的內存池_S_pool

 

486     return _S_pool;

487        }

488      };

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