C 高效能記憶體池,支援動態分配記憶體塊

2021-10-01 15:29:21 字數 4863 閱讀 4739

在c/c++中記憶體的管理是非常頭痛的事情,這裡作者不再多解釋,請參考這篇文章:作者也是參考這篇文章進行對記憶體池的改進和進化。

1、封裝乙個類用於管理記憶體池的使用如下,很容易看得懂,其實就是向記憶體池申請size個空間並進行構造,返回是首個元素的位址。釋放也是一樣,不過釋放多個的時候需要確保這多個元素的記憶體是連續的。

#pragma once

#include template>

class allocatemanager

//allocator申請空間

t * allocatejj(size_t size = 1)

//釋放並**空間

void destroy(t * node, size_t size = 1) }

//獲得當前記憶體池的大小

const size_t getmenorysize()

//獲得當前記憶體池的塊數

const size_t getblocksize()

};

rebind的設計跟c++stl裡的設計是同樣套路,stl設計**如下:

templateclass basic_string

: public _string_val<_elem _ax>

; ...

2、記憶體池設計**,下面會乙個乙個方法拋開說明

#pragma once

#include templateclass memorypool

; memorypool()

~memorypool() }

//申請空間

t * allocateone()

//申請一塊記憶體

if (m_currentslot >= m_laterslot)

return reinterpret_cast(m_currentslot++);

} /*動態分配空間,注意:分配超過2個空間會在塊裡面建立占用4位元組的空間存放陣列的指標,

這個空間不會被**,所以動態分配最好分配大空間才使用動態

*/ t * allocate(size_t size = 1)

; //申請乙個空間

if (size == 1)

return allocateone();

slot_pointer presult = nullptr;

/*先計算最後申請的塊空間夠不夠,不適用**的空間,因為**空間不是連續*/

int canusesize = reinterpret_cast(m_laterslot) + sizeof(slot_) - 1 - reinterpret_cast(m_currentslot);

/*空間不夠動態分配塊大小,不把上一塊剩餘的空間使用是因為空間是需要連續,

所以上一塊會繼續往前推供下次使用*/

m_blocksize++;

if (!m_headslot)//目前沒有一塊記憶體情況

else

return reinterpret_cast(presult);

} //使用空間

void construct(t * p, size_t size = 1)

//析構乙個物件

void destroy(t * p)

//**乙個空間

void deallocate(t * p, size_t count = 1)

; reinterpret_cast(p)->next = m_freeheadslot;

m_freeheadslot = reinterpret_cast(p);

} const size_t getmenorysize()

const size_t getblocksize()

private:

union slot_

; typedef slot_* slot_pointer;

typedef char* char_pointer;

slot_pointer m_freeheadslot;//空閒的空間頭部位置

slot_pointer m_headslot;//指向的頭位置

slot_pointer m_currentslot;//當前所指向的位置

slot_pointer m_laterslot;//指向最後乙個元素的開始位置

size_t m_menorysize;

size_t m_blocksize;

// 同步

std::mutex m_lock;

static_assert(blocksize > 0, "blocksize can not zero");

};

3、申請乙個空間,當**的記憶體沒有或記憶體塊空間不夠時,新開闢一塊記憶體,並將新記憶體放在表頭,返回新記憶體的頭位址,如果記憶體塊還有空間,那麼返回首個空餘的空間

//申請空間

t * allocateone()

//申請一塊記憶體

if (m_currentslot >= m_laterslot)

return reinterpret_cast(m_currentslot++);

}

4、當分配超過2個元素空間時,先判斷空閒塊的空間夠不夠分配,夠分配,不夠新開闢乙個大小跟申請元素個數一樣的記憶體塊,並將該塊記憶體向表頭置後,返回該快首位址。注意,由於分配多個元素的空間也就是分配乙個陣列,這個時候在下一步呼叫建構函式時會構造陣列物件,陣列物件會多乙個指標空間指向該陣列,所以申請n+1個元素時加上乙個指標的空間,否則會洩漏。

這個指標的空間是沒有用的,釋放和**空間是不會**這個指標,這樣它就會占用了記憶體塊乙個指標空間,就相當於磁碟分割槽有未分配的記憶體一樣,分配多個元素空間時這個是無法避免的。

/*動態分配空間,注意:分配超過2個空間會在塊裡面建立占用4位元組的空間存放陣列的指標,

這個空間不會被**,所以動態分配最好分配大空間才使用動態

*/ t * allocate(size_t size = 1)

; //申請乙個空間

if (size == 1)

return allocateone();

slot_pointer presult = nullptr;

/*先計算最後申請的塊空間夠不夠,不適用**的空間,因為**空間不是連續*/

int canusesize = reinterpret_cast(m_laterslot) + sizeof(slot_) - 1 - reinterpret_cast(m_currentslot);

/*空間不夠動態分配塊大小,不把上一塊剩餘的空間使用是因為空間是需要連續,

所以上一塊會繼續往前推供下次使用*/

m_blocksize++;

if (!m_headslot)//目前沒有一塊記憶體情況

else

return reinterpret_cast(presult);

}

其他小的方法就不介紹了,**也有注釋很容易看得懂。

5、效能測試

動態分配時,num1表示分配塊數,num2表示分配的每塊大小。

逐步申請和釋放一千萬個空間(元素為單位),速度如下,c++是最慢的,memorypool快樂接近20倍,memorypool動態分配會更快樂些(面對疾風吧)。

測試**:

#include #include #include #include #include #include"memorypool.h"

#include"allocatemanager.h"

using namespace std;

//動態分配時,num1表示塊數,num2表示每塊大小

#define num1 1000

#define num2 10000

class test

};void testbycjj()

} //根據物件從記憶體池釋放並**該空間

for (int i = 0; i < num1; i++) }

std::cout << "c++ time: ";

std::cout << (((double)clock() - start) / clocks_per_sec) << endl;

}void testbyone()

} for (int i = 0; i < num1; i++) }

std::cout << "memorypool one time: ";

std::cout << (((double)clock() - start) / clocks_per_sec);

std::cout << " 記憶體塊數量:" << memorypool.getblocksize();

std::cout << " 記憶體消耗(byte):" << memorypool.getmenorysize() << std::endl;

}void testbyblock()

} for (int i = 0; i < num1; i++) }

std::cout << "memorypool block time: ";

std::cout << (((double)clock() - start) / clocks_per_sec);

std::cout << " 記憶體塊數量:" << memorypool.getblocksize();

std::cout << " 記憶體消耗(byte):" << memorypool.getmenorysize() << std::endl;

}int main()

工程檔案鏈

記憶體動態分配

陣列的元素儲存於記憶體中連續的位置上。當乙個陣列被宣告時,它所需要的內存在編譯時就被分配。但是,你也可以使用動態記憶體分配在執行時為它分配記憶體。malloc所分配的是一塊連續的記憶體。例如,如果請求它分配100個位元組的記憶體,那麼它實際分配的記憶體就是100個連續的位元組,並不會分開位於兩塊或多...

動態分配記憶體

動態記憶體分配即分配記憶體大小在執行時才確定,一般在堆中分配。c語言動態記憶體分配相關的函式。include void malloc size t size malloc的使用比較直接,乙個成功的malloc呼叫返回分配的size大小的記憶體的指標。失敗時返回null並將錯誤 置為enomem。教材...

動態分配記憶體

動態分配記憶體 動態分配記憶體也可以分配儲存區,這種方式可以在程式執行的時候臨時決定分配的儲存區大小 為了管理動態分配的記憶體,就需要使用一組標準函式 為了使用這些標準函式,需要包含stdlib.h標頭檔案 malloc 函式可以動態分配一組連續的位元組 這個函式需要乙個整數型別引數表示分配的位元組...