一個簡易的C++內存管理器實現整體結構以下所示:linux
該內存分配器的剛開始使用是經過sc_pool_s *sc_create_pool (size_t size)
函數建立一個字節大小爲size的sc_pool_s
對象,該對象由一個鏈表結構的sc_pool_data_t
和一個指向sc_pool_large_s
的結構體指針組成,其中sc_pool_data_t
用來處理小內存申請的需求,而sc_pool_large_s
則用來處理大內存申請的請求,且根據須要動態的擴展,造成一個鏈表結構。c++
#define sc_align_ptr(p, a) \ (unsigned char *) (((unsigned long int ) (p) + ((unsigned long int ) a - 1)) & ~((unsigned long int ) a - 1))
這段代碼的意思就是返回一個以大小爲a
的內存對齊方式,要解釋這段代碼,假設裏面的變量都是unsigned long
類型的,將其簡化成以下形式:git
(p +(a - 1)) & ~(a - 1)
先解釋~(a - 1)
,假設如今的對齊方式是16字節的方式對齊(通常都是將地址2的冪次進行對齊),即a = 16
,如今將a - 1
取反後的二進制爲10000
,將這個二進制數與任何數相與,都會產生後4位爲0的二進制數,而其餘位數不變,這個數此時剛好就是a = 16
的倍數。而p + (a - 1)
則是要獲取比起始地址p
要大的數,且這個數要儘量的不會影響原來已經分配了內存的空間,但又不會比p
大太多從而形成內存碎片,則所加的數是a-1
知足該要求。github
例如此時p的基址爲17(假設從0開始分配,已經爲某處分配了17字節的大小的內存,如今從p=17開始申請內存)。p + (a - 1)
的值爲0...010001 + 0...01111 = 100000
,此時(p +(a - 1)) & ~(a - 1)
相與的結果是0...0100000
& 1...10000
=0...0100000
= 32;即地址不會從17開始,而只會從32開始,有利於快速讀取操做。函數
內存對齊方式的緣由.net
解釋指針
對於大多數語言來講,這部分實現是由編譯器來實現的(編譯器將每一個」數據單元「放在合適的內存位置上),可是C/C++太強大,太靈活了,容許你去幹預」內存對齊「。code
以以下程序作說明:對象
struct{ char a; char b; int c; } Struct1; struct{ char a; int c; char b; } Struct2; int main() { cout << "Struct1 : " << sizeof(Struct1) << endl; // Struct1 : 8 cout << "Struct2 : " << sizeof(Struct2) << endl; // Struct2 : 12 return 0; }
緣由是linux中默認對齊方式的值爲4,在struct1
中,前兩個字節表示共佔2字節的大小,第一塊內存的位置能夠放下,而後一個int
佔4個字節,而第一個內存裏只能容下兩個字節的數據存放,因此就會放到第二塊內存位置中去;同理,在結構體struct2
中,第一塊內存只能容納一個char
類型的字符,而4字節的int
要放到 第二塊內存裏,第三個char
此時只能放到 第三塊內存中去了。blog
結構體 | 內存塊1(4字節) | 內存塊2(4字節) | 內存塊3(4字節) |
---|---|---|---|
Struct1 |
a,b | c | |
Struct2 |
a | c | b |
通過內存對齊後,CPU的內存訪問速度大大提高。若是操做1字節的數據,能夠是任意地址;如果操做2字節的數據,若是開始地址在偶數地址,一次就能夠取2字節,若是開始地址在奇數,就要2次內存操做才能完成;若是操做4字節的數據,最好開始地址在能被4整除的數值上,這樣能夠用一條32位的內存操做指令完成。一樣,8字節的開始位置最好的能被8整除的數值上,這樣能夠用一條64位的內存操做指令完成。就是說,若是對齊了,一次就能夠完成,不對齊,就可能屢次才能完成。這樣,只要你在結構體裏對象之間能處理好對齊,你的數據就能操做得很快。
功能:返回size字節的動態內存,預對齊內存的分配。posix_memalign函數的用法相似於malloc的用法,由posix_memalign分配的內存空間,須要由free釋放。
頭文件:#include <stdlib.h>
函數原型:int posix_memalign (void **memptr,size_t alignment,size_t size);
參數:
返回值:調用posix_memalign( )成功時會返回size字節的動態內存,而且這塊內存的地址是alignment的倍數。參數alignment必須是2的冪,仍是void指針的大小的倍數。返回的內存塊的地址放在了memptr裏面,函數返回值是0。
調用失敗時,沒有內存會被分配,memptr的值沒有被定義,返回以下錯誤碼之一:
EINVAL:參數不是2的冪,或者不是void指針的倍數。
ENOMEM:沒有足夠的內存去知足函數的請求。
int main(){ sc_pool_t *pool = sc_create_pool(1024); int i=0; for(i=0;i<10000;i++){ sc_pcalloc (pool,800 * 10); } sleep(5); sc_destroy_pool (pool); sleep(5); }
該內存分配器的源代碼地址以下:github