簡易內存分配器的實現

一個簡易的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++

一些其餘內容的說明

1. 內存對齊方式的實現

#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

  1. 內存對齊後,能夠更方便讀取的存取數據。
  2. 不是所有硬件平臺都能訪問隨意地址上的隨意地址,爲了兼容性,須要作內存對齊。

解釋指針

​ 對於大多數語言來講,這部分實現是由編譯器來實現的(編譯器將每一個」數據單元「放在合適的內存位置上),可是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位的內存操做指令完成。就是說,若是對齊了,一次就能夠完成,不對齊,就可能屢次才能完成。這樣,只要你在結構體裏對象之間能處理好對齊,你的數據就能操做得很快。

2. 函數 posix_memalign() 使用說明

功能:返回size字節的動態內存,預對齊內存的分配。posix_memalign函數的用法相似於malloc的用法,由posix_memalign分配的內存空間,須要由free釋放。

頭文件:#include <stdlib.h>

函數原型:int posix_memalign (void **memptr,size_t alignment,size_t size);

參數:

  • memptr 分配好的內存空間的首地址
  • alignment 對齊邊界,Linux中,32位系統是8字節,64位系統是16字節
  • size 指定分配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

參考資料

函數 posix_memalign() 使用說明

相關文章
相關標籤/搜索