提高C++性能的编程技术笔记:多线程内存池+测试代码
生活随笔
收集整理的這篇文章主要介紹了
提高C++性能的编程技术笔记:多线程内存池+测试代码
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
為了使多個線程并發(fā)地分配和釋放內(nèi)存,必須在分配器方法中添加互斥鎖。
全局內(nèi)存管理器(通過new()和delete()實現(xiàn))是通用的,因此它的開銷也非常大。
因為單線程內(nèi)存管理器要比多線程內(nèi)存管理器快的多,所以如果要分配的大多數(shù)內(nèi)存塊限于單線程中使用,那么可以顯著提升性能。
如果開發(fā)了一套有效的單線程分配器,那么通過模板可以方便地將它們擴展到多線程環(huán)境中。
以下是測試代碼(multi_threaded_memory_pool.cpp):
#include "multi_threaded_memory_pool.hpp"
#include <iostream>
#include <chrono>
#include <string>
#include <mutex>namespace multi_threaded_memory_pool_ {// reference: 《提高C++性能的編程技術(shù)》:第七章:多線程內(nèi)存池class Rational1 {
public:Rational1(int a = 0, int b = 1) : n(a), d(b) {}
private:int n; // 分子int d; // 分母
};// 單線程可變大小內(nèi)存管理器:
// MemoryChunk類取代之前版本中使用的NextOnFreeList類,它用來把不同大小的內(nèi)存塊連接起來形成塊序列
class MemoryChunk {
public:MemoryChunk(MemoryChunk* nextChunk, size_t chunkSize);// 析構(gòu)函數(shù)釋放構(gòu)造函數(shù)獲得的內(nèi)存空間~MemoryChunk() { delete [] mem; }inline void* alloc(size_t size);inline void free(void* someElement);// 指向列表下一內(nèi)存塊的指針MemoryChunk* nextMemChunk() { return next; }// 當前內(nèi)存塊剩余空間大小size_t spaceAvailable() { return chunkSize - bytesAlreadyAllocated; }// 這是一個內(nèi)存塊的默認大小enum { DEFAULT_CHUNK_SIZE = 4096 };private:MemoryChunk* next;void* mem;// 一個內(nèi)存塊的默認大小size_t chunkSize;// 當前內(nèi)存塊中已分配的字節(jié)數(shù)size_t bytesAlreadyAllocated;
};// 構(gòu)造函數(shù)首先確定內(nèi)存塊的適當大小,然后根據(jù)這個大小從堆上分配私有存儲空間
// MemoryChunk將next成員指向輸入?yún)?shù)nextChunk, nextChunk是列表先前的頭部
MemoryChunk::MemoryChunk(MemoryChunk* nextChunk, size_t reqSize)
{chunkSize = (reqSize > DEFAULT_CHUNK_SIZE) ? reqSize : DEFAULT_CHUNK_SIZE;next = nextChunk;bytesAlreadyAllocated = 0;mem = new char[chunkSize];
}// alloc函數(shù)處理內(nèi)存分配請求,它返回一個指針,該指針指向mem所指向的MemoryChunk私有存儲空間中的可用空間。
// 該函數(shù)通過更新該塊中已分配的字節(jié)數(shù)來記錄可用空間的大小
void* MemoryChunk::alloc(size_t requestSize)
{void* addr = static_cast<void*>(static_cast<char*>(mem) + bytesAlreadyAllocated);bytesAlreadyAllocated += requestSize;return addr;
}// 在該實現(xiàn)中,不用擔心空閑內(nèi)存段的釋放。當對象被刪除后,整個內(nèi)存塊將被釋放并且返回到堆上
inline void MemoryChunk::free(void* doomed)
{
}// MemoryChunk只是一個輔助類,ByteMemoryPoll類用它來實現(xiàn)可變大小的內(nèi)存管理
class ByteMemoryPool {
public:ByteMemoryPool(size_t initSize = MemoryChunk::DEFAULT_CHUNK_SIZE);~ByteMemoryPool();// 從私有內(nèi)存池分配內(nèi)存inline void* alloc(size_t size);// 釋放先前從內(nèi)存池中分配的內(nèi)存inline void free(void* someElement);private:// 內(nèi)存塊列表,它是我們的私有存儲空間MemoryChunk* listOfMemoryChunks = nullptr;// 向我們的私有存儲空間添加一個內(nèi)存塊void expandStorage(size_t reqSize);
};// 雖然內(nèi)存塊列表可能包含多個塊,但只有第一塊擁有可用于分配的內(nèi)存。其它塊表示已分配的內(nèi)存。
// 列表的首個元素是唯一能夠分配可以內(nèi)存的塊。// 構(gòu)造函數(shù)接收initSize參數(shù)來設(shè)定一個內(nèi)存塊的大小,即構(gòu)造函數(shù)借此來設(shè)置單個內(nèi)存塊的大小。
// expandStorage方法使listOfMemoryChunks指向一個已分配的MemoryChunk對象
// 創(chuàng)建ByteMemoryPool對象,生成私有存儲空間
ByteMemoryPool::ByteMemoryPool(size_t initSize)
{expandStorage(initSize);
}// 析構(gòu)函數(shù)遍歷內(nèi)存塊列表并且刪除它們
ByteMemoryPool::~ByteMemoryPool()
{MemoryChunk* memChunk = listOfMemoryChunks;while (memChunk) {listOfMemoryChunks = memChunk->nextMemChunk();delete memChunk;memChunk = listOfMemoryChunks;}
}// alloc函數(shù)確保有足夠的可用空間,而把分配任務(wù)托付給列表頭的MemoryChunk
void* ByteMemoryPool::alloc(size_t requestSize)
{size_t space = listOfMemoryChunks->spaceAvailable();if (space < requestSize) {expandStorage(requestSize);}return listOfMemoryChunks->alloc(requestSize);
}// 釋放之前分配的內(nèi)存的任務(wù)被委派給列表頭部的MemoryChunk來完成
// MemoryChunk::free不做任何事情,因為ByteMemoryPool的實現(xiàn)不會重用之前分配的內(nèi)存。如果需要更多內(nèi)存,
// 我們將創(chuàng)建新的內(nèi)存塊以便今后分配使用。在內(nèi)存池被銷毀時,內(nèi)存釋放回堆中。ByteMemoryPool析構(gòu)函數(shù)
// 釋放所有的內(nèi)存塊到堆中
inline void ByteMemoryPool::free(void* doomed)
{listOfMemoryChunks->free(doomed);
}// 若遇到內(nèi)存塊用盡這種不太可能的情況,我們通過創(chuàng)建新的內(nèi)存塊并把它添加到內(nèi)存塊列表的頭部來擴展它
void ByteMemoryPool::expandStorage(size_t reqSize)
{listOfMemoryChunks = new MemoryChunk(listOfMemoryChunks, reqSize);
}// 多線程內(nèi)存池實現(xiàn)
template<class POOLTYPE, class LOCK>
class MTMemoryPool {
public:// 從freeList里分配一個元素inline void* alloc(size_t size);// 返回一個元素給freeListinline void free(void* someElement);private:POOLTYPE stPool; // 單線程池LOCK theLock;
};// alloc方法將分配任務(wù)委托給內(nèi)存池成員,而將鎖定任務(wù)委托給鎖成員
template<class M, class L>
inline void* MTMemoryPool<M, L>::alloc(size_t size)
{void* mem;theLock.lock();mem = stPool.alloc(size);theLock.unlock();return mem;
}template<class M, class L>
inline void MTMemoryPool<M, L>::free(void* doomed)
{theLock.lock();stPool.free(doomed);theLock.unlock();
}class ABCLock { // 抽象基類
public:virtual ~ABCLock() {}virtual void lock() = 0;virtual void unlock() = 0;
};class MutexLock : public ABCLock {
public:MutexLock() {}~MutexLock() {}inline void lock() { mtx.lock(); }inline void unlock() { mtx.unlock(); }private:std::mutex mtx;
};class Rational2 {
public:Rational2(int a = 0, int b = 1) : n(a),d(b) {}void* operator new(size_t size) { return memPool->alloc(size); }void operator delete(void* doomed, size_t size) { memPool->free(doomed); }static void newMemPool() { memPool = new MTMemoryPool<ByteMemoryPool, MutexLock>; }static void deleteMemPool() { delete memPool; }private:int n; // 分子int d; // 分母static MTMemoryPool<ByteMemoryPool, MutexLock>* memPool;
};MTMemoryPool<ByteMemoryPool, MutexLock>* Rational2::memPool = nullptr;///
// 多線程內(nèi)存池實現(xiàn)應(yīng)用在單線程環(huán)境中
class DummyLock : public ABCLock {
public:inline void lock() {}inline void unlock() {}
};class Rational3 {
public:Rational3(int a = 0, int b = 1) : n(a),d(b) {}void* operator new(size_t size) { return memPool->alloc(size); }void operator delete(void* doomed, size_t size) { memPool->free(doomed); }static void newMemPool() { memPool = new MTMemoryPool<ByteMemoryPool, DummyLock>; }static void deleteMemPool() { delete memPool; }private:int n; // 分子int d; // 分母static MTMemoryPool<ByteMemoryPool, DummyLock>* memPool;
};MTMemoryPool<ByteMemoryPool, DummyLock>* Rational3::memPool = nullptr;int test_multi_threaded_memory_pool_1()
{using namespace std::chrono;high_resolution_clock::time_point time_start, time_end;const int cycle_number1{10000}, cycle_number2{1000};{ // 測試全局函數(shù)new()和delete()的基準性能Rational1* array[cycle_number2];time_start = high_resolution_clock::now();for (int j =0; j < cycle_number1; ++j) {for (int i =0; i < cycle_number2; ++i) {array[i] = new Rational1(i);}for (int i = 0; i < cycle_number2; ++i) {delete array[i];} }time_end = high_resolution_clock::now();fprintf(stdout, "global function new/delete time spent: %f seconds\n",(duration_cast<duration<double>>(time_end - time_start)).count());
}{ // 多線程內(nèi)存池測試代碼Rational2* array[cycle_number2];time_start = high_resolution_clock::now();Rational2::newMemPool();for (int j = 0; j < cycle_number1; ++j) {for (int i = 0; i < cycle_number2; ++i) {array[i] = new Rational2(i);}for (int i = 0; i < cycle_number2; ++i) {delete array[i];}}Rational2::deleteMemPool();time_end = high_resolution_clock::now();fprintf(stdout, "multi-threaded variable-size memory manager time spent: %f seconds\n",(duration_cast<duration<double>>(time_end - time_start)).count());
}{ // 多線程內(nèi)存池應(yīng)用在單線程環(huán)境下測試代碼Rational3* array[cycle_number2];time_start = high_resolution_clock::now();Rational3::newMemPool();for (int j = 0; j < cycle_number1; ++j) {for (int i = 0; i < cycle_number2; ++i) {array[i] = new Rational3(i);}for (int i = 0; i < cycle_number2; ++i) {delete array[i];}}Rational3::deleteMemPool();time_end = high_resolution_clock::now();fprintf(stdout, "multi-threaded variable-size memory manager in single-threaded environment time spent: %f seconds\n",(duration_cast<duration<double>>(time_end - time_start)).count());
}return 0;
}} // namespace multi_threaded_memory_pool_
執(zhí)行結(jié)果如下:
GitHub:https://github.com/fengbingchun/Messy_Test ?
總結(jié)
以上是生活随笔為你收集整理的提高C++性能的编程技术笔记:多线程内存池+测试代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 提高C++性能的编程技术笔记:单线程内存
- 下一篇: 代码覆盖测试工具Kcov简介及使用