- void* aligned_malloc(size_t size, size_t align)
- {
- void* raw_malloc_ptr; //初始分配的地址
- void* aligned_ptr; //最終我們獲得的alignment地址
- if( align & (align - 1) ) //如果alignment不是2的n次方,返回
- {
- errno = EINVAL;
- return ( (void*)0 );
- }
- if( 0 == size )
- {
- return ( (void*)0 );
- }
- //將alignment置爲至少爲2*sizeof(void*),一種優化做法。
- if( align < 2*sizeof(void*) )
- {
- align = 2 * sizeof(void*);
- }
- raw_malloc_ptr = malloc(size + align);
- if( !raw_malloc_ptr )
- {
- return ( (void*)0 );
- }
- //Align We have at least sizeof (void *) space below malloc'd ptr.
- aligned_ptr = (void*) ( ((size_t)raw_malloc_ptr + align) & ~((size_t)align - 1));
- ( (void**)aligned_ptr )[-1] = raw_malloc_ptr;
- return aligned_ptr;
- }
- void* aligned_free(void * aligned_ptr)
- {
- if( aligned_ptr )
- {
- free( ((void**)aligned_ptr)[-1] );
- }
- }
再給出一套對比一下,可能講的更詳細:
- void* aligned_malloc(size_t size, int alignment)
- {
- // 分配足夠的內存, 這裏的算法很經典, 早期的STL中使用的就是這個算法
- // 首先是維護FreeBlock指針佔用的內存大小
- const int pointerSize = sizeof (void*);
- // alignment - 1 + pointerSize這個是FreeBlock內存對齊需要的內存大小
- // 前面的例子sizeof(T) = 20, __alignof(T) = 16,
- // g_MaxNumberOfObjectsInPool = 1000
- // 那麼調用本函數就是alignedMalloc(1000 * 20, 16)
- // 那麼alignment - 1 + pointSize = 19
- const int requestedSize = size + alignment - 1 + pointerSize;
- // 分配的實際大小就是20000 + 19 = 20019
- void* raw = malloc(requestedSize);
- // 這裏實Pool真正爲對象實例分配的內存地址
- uintptr_t start = (uintptr_t) raw + pointerSize;
- // 向上舍入操作
- // 解釋一下, __ALIGN - 1指明的是實際內存對齊的粒度
- // 例如__ALIGN = 8時, 我們只需要7就可以實際表示8個數(0~7)
- // 那麼~(__ALIGN - 1)就是進行舍入的粒度
- // 我們將(bytes) + __ALIGN-1)就是先進行進位, 然後截斷
- // 這就保證了我是向上舍入的
- // 例如byte = 100, __ALIGN = 8的情況
- // ~(__ALIGN - 1) = (1 000)B
- // ((bytes) + __ALIGN-1) = (1 101 011)B
- // (((bytes) + __ALIGN-1) & ~(__ALIGN - 1)) = (1 101 000 )B = (104)D
- // 104 / 8 = 13, 這就實現了向上舍入
- // 對於byte剛好滿足內存對齊的情況下, 結果保持byte大小不變
- // 記得《Hacker's Delight》上面有相關的計算
- // 這個表達式與下面給出的等價
- // ((((bytes) + _ALIGN - 1) * _ALIGN) / _ALIGN)
- // 但是SGI STL使用的方法效率非常高
- void* aligned = (void*) ((start + alignment - 1) & ~(alignment - 1));
- // 這裏維護一個指向malloc()真正分配的內存
- *(void**) ((uintptr_t) aligned - pointerSize) = raw;
- // 返回實例對象真正的地址
- return aligned;
- }
- // 這裏是內部維護的內存情況
- // 這裏滿足內存對齊要求
- // |
- // ----------------------------------------------------------------------
- // | 內存對齊填充 | 維護的指針 | 對象1 | 對象2 | 對象3 | ...... | 對象n |
- // ----------------------------------------------------------------------
- // ^ | 指向malloc()分配的地址起點
- // | |
- // -----------------------
- void aligned_free(void* aligned)
- {
- // 釋放操作很簡單了, 參見上圖
- void* raw = *(void**) ((uintptr_t) aligned - sizeof (void*));
- free(raw);
- }
- bool isAligned(void* data, int alignment)
- {
- // 又是一個經典算法, 參見<Hacker's Delight>
- return ((uintptr_t) data & (alignment - 1)) == 0;
- }
注:
<Hacker's Delight>這是第一本試圖揭開計算機運算神祕面紗的書,極其適合於編譯器編寫者、庫開發者、反工程愛好者研讀,將給大家展示一些鮮爲人知但非常有意義的二進制編碼技巧以及底層Algorithms技巧,其內容超級強悍。