在給定的內存buffer上創建內存管理機制,根據用戶需求從該buffer上分配內存或者將已經分配的內存釋放回buffer中。ios
儘可能減小內存碎片,平均效率高於C語言的malloc和free。windows
將buffer分爲四部分,第1部分是mem_pool結構體;第2部分是內存映射表;第3部分是內存chunk結構體緩衝區;第4部分是實際可分配的內存區。整個buffer結構圖如圖1所示:數據結構
圖1 內存buffer結構圖app
第1部分的做用是能夠經過該mem_pool結構體控制整個內存池。性能
第2部分的做用是記錄第4部分,即實際可分配的內存區的使用狀況。表中的每個單元表示一個固定大小的內存塊(block),多個連續的block組成一個chunk,每一個block的詳細結構如圖2所示:測試
圖2 memory block結構圖spa
其中count表示該block後面的與該block同屬於一個chunk的blokc的個數,start表示該block所在的chunk的起始block索引。其實start這個域只有在每一個chunk的最後一個block中才會用到(用於從當前chunk尋找前一個chunk的起始位置),而pmem_chunk則是一個指針,指向一個mem_chunk結構體。任意一塊大小的內存都會被取向上整到block大小的整數倍。.net
第3部分是一個mem_chunk pool,其做用是存儲整個程序可用的mem_chunk結構體。mem_chunk pool中的mem_chunk被組織成雙向鏈表結構(快速插入和刪除)。每一個mem_chunk結構圖如圖3所示:設計
圖3 memory chunk結構圖指針
其中pmem_block指向該chunk在內存映射表中的位置,others表示其餘一些域,不一樣的實現對應該域的內容略有不一樣。
第4部分就是實際能夠被分配給用戶的內存。
整個內存池管理程序除了這四部分外,還有一個重要的內容就是memory chunk set。雖然其中的每一個元素都來自mem_chunk pool,可是它與mem_chunk pool的不一樣之處在於其中的每一個memory chunk中記錄了當前可用的一塊內存的相關信息。而mem_chunk pool中的memory chunk的內容是無定以的。能夠這樣理解mem_chunk pool與memory chunk set:mem_chunk pool是爲memory chunk set分配內存的「內存池」,只是該「內存池」每次分配的內存大小是固定的,爲mem_chunk結構體的大小。內存池程序主要是經過搜索這個memory chunk set來獲取可被分配的內存。在memory chunk set上創建不一樣的數據結構就構成了不一樣的內存池實現方法,同時也致使了不一樣的搜索效率,直接影響內存池的性能,本文稍後會介紹兩種內存池的實現。
本文設計的方法只能在必定程度上減小內存碎片,並不能完全消除內存碎片。具體方法以下:
在用戶釋放內存時,嘗試將該內存與其相鄰的內存合併。若是其相鄰內存爲未分配內存則合併成功,合併後做爲一整塊內存使用;如火其相鄰內存爲已分配內存則不能合併,該釋放的內存塊做爲一個獨立的內存塊被使用。
鏈表結構的內存池實現是指將memory chunk set實現爲雙鏈表結構。這種方法的優缺點以下:
優勢:釋放內存很快,O(1)複雜度。
缺點:分配內存較慢,O(n)複雜度。
綠色表示未使用的內存,紅色表示已經使用的內存。其中每一個block表示64B,這個值能夠根據具體須要設定。
圖4 內存池初始化狀態
圖5 第1次申請128B內存後
圖6 第n次申請、釋放內存後
圖7 釋放64B內存先後
大頂堆結構的內存池實現是指將memory chunk set實現爲大頂堆結構。這種方法的優缺點以下:
優勢:下降了分配內存的時間複雜度,O(log(n))。
缺點:增長了釋放內存的時間複雜度,O(log(n))。
綠色表示未使用的內存,紅色表示已經使用的內存。其中每一個block表示64B,這個值能夠根據具體須要設定。
圖8 內存池初始化狀態
圖9 第1次申請128B內存後
圖10 第n次申請、釋放內存後
圖11 釋放64B內存先後
(1) 生成n個隨機數,大小在64~1024之間,用於表示n個要分配的內存大小;
(2) 生成n個隨機數,取值 爲0或者1,表示每次分配內存後緊接着是否釋放內存;
(3) 測量C語言的malloc、free和本文兩種內存池執行n次隨機分配、釋放隨機大小內存的時間比ratio;
(4) 重複(3)m=200次,記錄每次活動的ratio,並繪製相應的曲線。
(1) 生成n個隨機數,大小在a~b之間(初始值a=64,b=1024),用於表示n個要分配的內存大小;
(2) 測量C語言的malloc、free和本文兩種內存池執行n次分配、釋放隨機大小內存的時間比ratio;
(3) 重複(2)m=512次,每次分配的內存容量的範圍比前一次大1024B,記錄每次得到的ratio,並繪製相應曲線。
圖12 鏈表結構內存池性能測試結果1
圖13 鏈表結構內存池性能測試結果2
圖14 大頂堆內存池性能測試結果1
圖15 大頂堆內存池性能測試結果2
圖16 兩種內存池性能測試結果比較1
圖17 兩種內存池性能測試結果比較2
從上面的內存池性能測試結果中能夠看出,相比C語言的malloc和free,內存池使得用戶分配內存和釋放內存的效率有了較大的提升,這一優點尤爲分配較大快的內存時體現的尤其突出。
同時也能夠看出大頂堆結夠的內存池的性能並不比鏈表結構的內存池性能高,反而低於鏈表結構內存池的性能。這再一次代表O(log(n))優於O(n)是有條件的。固然,本文的測試具備必定的侷限性,也許在其餘的測試案例中大頂堆結構的內存池性能會超越鏈表結構的內存池。
鏈表結構內存池:
MemoryPool.h
#ifndef _MEMORYPOOL_H
#define _MEMORYPOOL_H
#include <stdlib.h>
#define MINUNITSIZE 64
#define ADDR_ALIGN 8
#define SIZE_ALIGN MINUNITSIZE
struct memory_chunk;
typedef struct memory_block
{
size_t count;
size_t start;
memory_chunk* pmem_chunk;
}memory_block;
// 可用的內存塊結構體
typedef struct memory_chunk
{
memory_block* pfree_mem_addr;
memory_chunk* pre;
memory_chunk* next;
}memory_chunk;
// 內存池結構體
typedef struct MEMORYPOOL
{
void *memory;
size_t size;
memory_block* pmem_map;
memory_chunk* pfree_mem_chunk;
memory_chunk* pfree_mem_chunk_pool;
size_t mem_used_size; // 記錄內存池中已經分配給用戶的內存的大小
size_t mem_map_pool_count; // 記錄鏈表單元緩衝池中剩餘的單元的個數,個數爲0時不能分配單元給pfree_mem_chunk
size_t free_mem_chunk_count; // 記錄 pfree_mem_chunk鏈表中的單元個數
size_t mem_map_unit_count; //
size_t mem_block_count; // 一個 mem_unit 大小爲 MINUNITSIZE
}MEMORYPOOL, *PMEMORYPOOL;
/************************************************************************/
/* 生成內存池
* pBuf: 給定的內存buffer起始地址
* sBufSize: 給定的內存buffer大小
* 返回生成的內存池指針
/************************************************************************/
PMEMORYPOOL CreateMemoryPool(void* pBuf, size_t sBufSize);
/************************************************************************/
/* 暫時沒用
/************************************************************************/
void ReleaseMemoryPool(PMEMORYPOOL* ppMem) ;
/************************************************************************/
/* 從內存池中分配指定大小的內存
* pMem: 內存池 指針
* sMemorySize: 要分配的內存大小
* 成功時返回分配的內存起始地址,失敗返回NULL
/************************************************************************/
void* GetMemory(size_t sMemorySize, PMEMORYPOOL pMem) ;
/************************************************************************/
/* 從內存池中釋放申請到的內存
* pMem:內存池指針
* ptrMemoryBlock:申請到的內存起始地址
/************************************************************************/
void FreeMemory(void *ptrMemoryBlock, PMEMORYPOOL pMem) ;
#endif //_MEMORYPOOL_H
MemoryPool.cpp
#include "stdafx.h"
#include <memory.h>
#include "MemoryPool.h"
/************************************************************************/
/* 內存池起始地址對齊到ADDR_ALIGN字節
/************************************************************************/
size_t check_align_addr(void*& pBuf)
{
size_t align = 0;
size_t addr = (int)pBuf;
align = (ADDR_ALIGN - addr % ADDR_ALIGN) % ADDR_ALIGN;
pBuf = (char*)pBuf + align;
return align;
}
/************************************************************************/
/* 內存block大小對齊到MINUNITSIZE字節
/************************************************************************/
size_t check_align_block(size_t size)
{
size_t align = size % MINUNITSIZE;
return size - align;
}
/************************************************************************/
/* 分配內存大小對齊到SIZE_ALIGN字節
/************************************************************************/
size_t check_align_size(size_t size)
{
size = (size + SIZE_ALIGN - 1) / SIZE_ALIGN * SIZE_ALIGN;
return size;
}
/************************************************************************/
/* 如下是鏈表相關操做
/************************************************************************/
memory_chunk* create_list(memory_chunk* pool, size_t count)
{
if (!pool)
{
return NULL;
}
memory_chunk* head = NULL;
for (size_t i = 0; i < count; i++)
{
pool->pre = NULL;
pool->next = head;
if (head != NULL)
{
head->pre = pool;
}
head = pool;
pool++;
}
return head;
}
memory_chunk* front_pop(memory_chunk*& pool)
{
if (!pool)
{
return NULL;
}
memory_chunk* tmp = pool;
pool = tmp->next;
pool->pre = NULL;
return tmp;
}
void push_back(memory_chunk*& head, memory_chunk* element)
{
if (head == NULL)
{
head = element;
head->pre = element;
head->next = element;
return;
}
head->pre->next = element;
element->pre = head->pre;
head->pre = element;
element->next = head;
}
void push_front(memory_chunk*& head, memory_chunk* element)
{
element->pre = NULL;
element->next = head;
if (head != NULL)
{
head->pre = element;
}
head = element;
}
void delete_chunk(memory_chunk*& head, memory_chunk* element)
{
// 在雙循環鏈表中刪除元素
if (element == NULL)
{
return;
}
// element爲鏈表頭
else if (element == head)
{
// 鏈表只有一個元素
if (head->pre == head)
{
head = NULL;
}
else
{
head = element->next;
head->pre = element->pre;
head->pre->next = head;
}
}
// element爲鏈表尾
else if (element->next == head)
{
head->pre = element->pre;
element->pre->next = head;
}
else
{
element->pre->next = element->next;
element->next->pre = element->pre;
}
element->pre = NULL;
element->next = NULL;
}
/************************************************************************/
/* 內存映射表中的索引轉化爲內存起始地址
/************************************************************************/
void* index2addr(PMEMORYPOOL mem_pool, size_t index)
{
char* p = (char*)(mem_pool->memory);
void* ret = (void*)(p + index *MINUNITSIZE);
return ret;
}
/************************************************************************/
/* 內存起始地址轉化爲內存映射表中的索引
/************************************************************************/
size_t addr2index(PMEMORYPOOL mem_pool, void* addr)
{
char* start = (char*)(mem_pool->memory);
char* p = (char*)addr;
size_t index = (p - start) / MINUNITSIZE;
return index;
}
/************************************************************************/
/* 生成內存池
* pBuf: 給定的內存buffer起始地址
* sBufSize: 給定的內存buffer大小
* 返回生成的內存池指針
/************************************************************************/
PMEMORYPOOL CreateMemoryPool(void* pBuf, size_t sBufSize)
{
memset(pBuf, 0, sBufSize);
PMEMORYPOOL mem_pool = (PMEMORYPOOL)pBuf;
// 計算須要多少memory map單元格
size_t mem_pool_struct_size = sizeof(MEMORYPOOL);
mem_pool->mem_map_pool_count = (sBufSize - mem_pool_struct_size + MINUNITSIZE - 1) / MINUNITSIZE;
mem_pool->mem_map_unit_count = (sBufSize - mem_pool_struct_size + MINUNITSIZE - 1) / MINUNITSIZE;
mem_pool->pmem_map = (memory_block*)((char*)pBuf + mem_pool_struct_size);
mem_pool->pfree_mem_chunk_pool = (memory_chunk*)((char*)pBuf + mem_pool_struct_size + sizeof(memory_block) * mem_pool->mem_map_unit_count);
mem_pool->memory = (char*)pBuf + mem_pool_struct_size+ sizeof(memory_block) * mem_pool->mem_map_unit_count + sizeof(memory_chunk) * mem_pool->mem_map_pool_count;
mem_pool->size = sBufSize - mem_pool_struct_size - sizeof(memory_block) * mem_pool->mem_map_unit_count - sizeof(memory_chunk) * mem_pool->mem_map_pool_count;
size_t align = check_align_addr(mem_pool->memory);
mem_pool->size -= align;
mem_pool->size = check_align_block(mem_pool->size);
mem_pool->mem_block_count = mem_pool->size / MINUNITSIZE;
// 鏈表化
mem_pool->pfree_mem_chunk_pool = create_list(mem_pool->pfree_mem_chunk_pool, mem_pool->mem_map_pool_count);
// 初始化 pfree_mem_chunk,雙向循環鏈表
memory_chunk* tmp = front_pop(mem_pool->pfree_mem_chunk_pool);
tmp->pre = tmp;
tmp->next = tmp;
tmp->pfree_mem_addr = NULL;
mem_pool->mem_map_pool_count--;
// 初始化 pmem_map
mem_pool->pmem_map[0].count = mem_pool->mem_block_count;
mem_pool->pmem_map[0].pmem_chunk = tmp;
mem_pool->pmem_map[mem_pool->mem_block_count-1].start = 0;
tmp->pfree_mem_addr = mem_pool->pmem_map;
push_back(mem_pool->pfree_mem_chunk, tmp);
mem_pool->free_mem_chunk_count = 1;
mem_pool->mem_used_size = 0;
return mem_pool;
}
/************************************************************************/
/* 暫時沒用
/************************************************************************/
void ReleaseMemoryPool(PMEMORYPOOL* ppMem)
{
}
/************************************************************************/
/* 從內存池中分配指定大小的內存
* pMem: 內存池 指針
* sMemorySize: 要分配的內存大小
* 成功時返回分配的內存起始地址,失敗返回NULL
/************************************************************************/
void* GetMemory(size_t sMemorySize, PMEMORYPOOL pMem)
{
sMemorySize = check_align_size(sMemorySize);
size_t index = 0;
memory_chunk* tmp = pMem->pfree_mem_chunk;
for (index = 0; index < pMem->free_mem_chunk_count; index++)
{
if (tmp->pfree_mem_addr->count * MINUNITSIZE >= sMemorySize)
{
break;
}
tmp = tmp->next;
}
if (index == pMem->free_mem_chunk_count)
{
return NULL;
}
pMem->mem_used_size += sMemorySize;
if (tmp->pfree_mem_addr->count * MINUNITSIZE == sMemorySize)
{
// 當要分配的內存大小與當前chunk中的內存大小相同時,從pfree_mem_chunk鏈表中刪除此chunk
size_t current_index = (tmp->pfree_mem_addr - pMem->pmem_map);
delete_chunk(pMem->pfree_mem_chunk, tmp);
tmp->pfree_mem_addr->pmem_chunk = NULL;
push_front(pMem->pfree_mem_chunk_pool, tmp);
pMem->free_mem_chunk_count--;
pMem->mem_map_pool_count++;
return index2addr(pMem, current_index);
}
else
{
// 當要分配的內存小於當前chunk中的內存時,更改pfree_mem_chunk中相應chunk的pfree_mem_addr
// 複製當前mem_map_unit
memory_block copy;
copy.count = tmp->pfree_mem_addr->count;
copy.pmem_chunk = tmp;
// 記錄該block的起始和結束索引
memory_block* current_block = tmp->pfree_mem_addr;
current_block->count = sMemorySize / MINUNITSIZE;
size_t current_index = (current_block - pMem->pmem_map);
pMem->pmem_map[current_index+current_block->count-1].start = current_index;
current_block->pmem_chunk = NULL; // NULL表示當前內存塊已被分配
// 當前block被一分爲二,更新第二個block中的內容
pMem->pmem_map[current_index+current_block->count].count = copy.count - current_block->count;
pMem->pmem_map[current_index+current_block->count].pmem_chunk = copy.pmem_chunk;
// 更新原來的pfree_mem_addr
tmp->pfree_mem_addr = &(pMem->pmem_map[current_index+current_block->count]);
size_t end_index = current_index + copy.count - 1;
pMem->pmem_map[end_index].start = current_index + current_block->count;
return index2addr(pMem, current_index);
}
}
/************************************************************************/
/* 從內存池中釋放申請到的內存
* pMem:內存池指針
* ptrMemoryBlock:申請到的內存起始地址
/************************************************************************/
void FreeMemory(void *ptrMemoryBlock, PMEMORYPOOL pMem)
{
size_t current_index = addr2index(pMem, ptrMemoryBlock);
size_t size = pMem->pmem_map[current_index].count * MINUNITSIZE;
// 判斷與當前釋放的內存塊相鄰的內存塊是否能夠與當前釋放的內存塊合併
memory_block* pre_block = NULL;
memory_block* next_block = NULL;
memory_block* current_block = &(pMem->pmem_map[current_index]);
// 第一個
if (current_index == 0)
{
if (current_block->count < pMem->mem_block_count)
{
next_block = &(pMem->pmem_map[current_index+current_block->count]);
// 若是後一個內存塊是空閒的,合併
if (next_block->pmem_chunk != NULL)
{
next_block->pmem_chunk->pfree_mem_addr = current_block;
pMem->pmem_map[current_index+current_block->count+next_block->count-1].start = current_index;
current_block->count += next_block->count;
current_block->pmem_chunk = next_block->pmem_chunk;
next_block->pmem_chunk = NULL;
}
// 若是後一塊內存不是空閒的,在pfree_mem_chunk中增長一個chunk
else
{
memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);
new_chunk->pfree_mem_addr = current_block;
current_block->pmem_chunk = new_chunk;
push_back(pMem->pfree_mem_chunk, new_chunk);
pMem->mem_map_pool_count--;
pMem->free_mem_chunk_count++;
}
}
else
{
memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);
new_chunk->pfree_mem_addr = current_block;
current_block->pmem_chunk = new_chunk;
push_back(pMem->pfree_mem_chunk, new_chunk);
pMem->mem_map_pool_count--;
pMem->free_mem_chunk_count++;
}
}
// 最後一個
else if (current_index == pMem->mem_block_count-1)
{
if (current_block->count < pMem->mem_block_count)
{
pre_block = &(pMem->pmem_map[current_index-1]);
size_t index = pre_block->count;
pre_block = &(pMem->pmem_map[index]);
// 若是前一個內存塊是空閒的,合併
if (pre_block->pmem_chunk != NULL)
{
pMem->pmem_map[current_index+current_block->count-1].start = current_index - pre_block->count;
pre_block->count += current_block->count;
current_block->pmem_chunk = NULL;
}
// 若是前一塊內存不是空閒的,在pfree_mem_chunk中增長一個chunk
else
{
memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);
new_chunk->pfree_mem_addr = current_block;
current_block->pmem_chunk = new_chunk;
push_back(pMem->pfree_mem_chunk, new_chunk);
pMem->mem_map_pool_count--;
pMem->free_mem_chunk_count++;
}
}
else
{
memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);
new_chunk->pfree_mem_addr = current_block;
current_block->pmem_chunk = new_chunk;
push_back(pMem->pfree_mem_chunk, new_chunk);
pMem->mem_map_pool_count--;
pMem->free_mem_chunk_count++;
}
}
else
{
next_block = &(pMem->pmem_map[current_index+current_block->count]);
pre_block = &(pMem->pmem_map[current_index-1]);
size_t index = pre_block->start;
pre_block = &(pMem->pmem_map[index]);
bool is_back_merge = false;
if (next_block->pmem_chunk == NULL && pre_block->pmem_chunk == NULL)
{
memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);
new_chunk->pfree_mem_addr = current_block;
current_block->pmem_chunk = new_chunk;
push_back(pMem->pfree_mem_chunk, new_chunk);
pMem->mem_map_pool_count--;
pMem->free_mem_chunk_count++;
}
// 後一個內存塊
if (next_block->pmem_chunk != NULL)
{
next_block->pmem_chunk->pfree_mem_addr = current_block;
pMem->pmem_map[current_index+current_block->count+next_block->count-1].start = current_index;
current_block->count += next_block->count;
current_block->pmem_chunk = next_block->pmem_chunk;
next_block->pmem_chunk = NULL;
is_back_merge = true;
}
// 前一個內存塊
if (pre_block->pmem_chunk != NULL)
{
pMem->pmem_map[current_index+current_block->count-1].start = current_index - pre_block->count;
pre_block->count += current_block->count;
if (is_back_merge)
{
delete_chunk(pMem->pfree_mem_chunk, current_block->pmem_chunk);
push_front(pMem->pfree_mem_chunk_pool, current_block->pmem_chunk);
pMem->free_mem_chunk_count--;
pMem->mem_map_pool_count++;
}
current_block->pmem_chunk = NULL;
}
}
pMem->mem_used_size -= size;
}
MemoryPoolTest.cpp
// memory pool test.cpp : Defines the entry point for the console application.
#include <tchar.h>
#include "MemoryPool.h"
#include <iostream>
#include <windows.h>
#include <vector>
#include <time.h>
#include <math.h>
#include <fstream>
using namespace std;
int break_time = 0;
// 檢測內存池相關參數
void check_mem_pool(int& max_chunk_size, int& free_chunk_count, int& min_chunk_size, int& total_free_mem, MEMORYPOOL* mem_pool)
{
memory_chunk* head = mem_pool->pfree_mem_chunk;
memory_chunk* tmp = head;
free_chunk_count = 0;
total_free_mem = 0;
max_chunk_size = 0;
min_chunk_size = 500*1024*1024;
if (head == NULL)
{
min_chunk_size = 0;
return;
}
while (tmp->next != head)
{
free_chunk_count++;
total_free_mem += tmp->pfree_mem_addr->count * MINUNITSIZE;
if (tmp->pfree_mem_addr->count * MINUNITSIZE > max_chunk_size )
{
max_chunk_size = tmp->pfree_mem_addr->count * MINUNITSIZE;
}
if (tmp->pfree_mem_addr->count * MINUNITSIZE < min_chunk_size)
{
min_chunk_size = tmp->pfree_mem_addr->count * MINUNITSIZE;
}
tmp = tmp->next;
}
free_chunk_count++;
total_free_mem += tmp->pfree_mem_addr->count * MINUNITSIZE;
if (tmp->pfree_mem_addr->count * MINUNITSIZE > max_chunk_size )
{
max_chunk_size = tmp->pfree_mem_addr->count * MINUNITSIZE;
}
if (tmp->pfree_mem_addr->count * MINUNITSIZE < min_chunk_size)
{
min_chunk_size = tmp->pfree_mem_addr->count * MINUNITSIZE;
}
}
// 申請後緊接着釋放
double test_mem_pool_perf_1(PMEMORYPOOL mem_pool, int iter, int* sizes)
{
cout << "*********************test_mem_pool_perf_1*********************" << endl;
LARGE_INTEGER litmp;
LONGLONG QPart1, QPart2;
double t;
double dfMinus, dfFreq;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 得到計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 得到初始值
for (int i = 0; i < iter; i++)
{
void *p = GetMemory(sizes[i], mem_pool);
if (p == NULL)
{
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << sizes[i] << " Byte" << endl;
cout << "total memory is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;
int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;
check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);
cout << "check memory pool result:" << endl;
cout << "free_chunk_count: " << free_chunk_count << endl
<< "total_free_mem: " << total_free_mem << endl
<< "max_chunk_size: " << max_chunk_size << endl
<< "min_chunk_size: " << min_chunk_size << endl;
break;
}
FreeMemory(p, mem_pool);
}
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//得到停止值
dfMinus = (double)(QPart2-QPart1);
t = dfMinus / dfFreq;// 得到對應的時間值,單位爲秒
cout << "test_mem_pool_perf_1: iter = " << iter << endl;
cout << "time: " << t << endl;
cout << "*********************test_mem_pool_perf_1*********************" << endl << endl << endl;
return t;
}
double test_std_perf_1(int iter, int* sizes)
{
cout << "*********************test_std_perf_1*********************" << endl;
LARGE_INTEGER litmp;
LONGLONG QPart1, QPart2;
double t;
double dfMinus, dfFreq;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 得到計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 得到初始值
for (int i = 0; i < iter; i++)
{
void *p = malloc(sizes[i]);
if (p == NULL)
{
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << sizes[i] << " Byte" << endl;
break;
}
free(p);
}
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//得到停止值
dfMinus = (double)(QPart2-QPart1);
t = dfMinus / dfFreq;// 得到對應的時間值,單位爲秒
cout << "test_std_perf_1: iter = " << iter << endl;
cout << "time: " << t << endl;
cout << "*********************test_std_perf_1*********************" << endl << endl << endl;
return t;
}
// 連續申請iter/2次,而後釋放全部申請內存;再重複一次
double test_mem_pool_perf_2(PMEMORYPOOL mem_pool, int iter, int size)
{
cout << "*********************test_mem_pool_perf_2*********************" << endl;
LARGE_INTEGER litmp;
LONGLONG QPart1, QPart2;
double t;
double dfMinus, dfFreq;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 得到計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 得到初始值
void **p = new void*[iter];
if (p == NULL)
{
cout << "new faild" << endl;
return -1;
}
int count = 0;
for (int i = 0; i < iter/2; i++)
{
p[i] = GetMemory(size, mem_pool);
if (p[i] == NULL)
{
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;
cout << "total memory is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;
int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;
check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);
cout << "check memory pool result:" << endl;
cout << "free_chunk_count: " << free_chunk_count << endl
<< "total_free_mem: " << total_free_mem << endl
<< "max_chunk_size: " << max_chunk_size << endl
<< "min_chunk_size: " << min_chunk_size << endl;
break;
}
count++;
}
for (int i = 0; i < count; i++)
{
FreeMemory(p[i], mem_pool);
}
count = 0;
for (int i = 0; i < iter/2; i++)
{
p[i] = GetMemory(size, mem_pool);
if (p[i] == NULL)
{
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;
cout << "total memory is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;
int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;
check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);
cout << "check memory pool result:" << endl;
cout << "free_chunk_count: " << free_chunk_count << endl
<< "total_free_mem: " << total_free_mem << endl
<< "max_chunk_size: " << max_chunk_size << endl
<< "min_chunk_size: " << min_chunk_size << endl;
break;
}
count++;
}
for (int i = 0; i < count; i++)
{
if (p[i] == NULL)
{
cout << i << endl;
break;
}
FreeMemory(p[i], mem_pool);
}
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//得到停止值
dfMinus = (double)(QPart2-QPart1);
t = dfMinus / dfFreq;// 得到對應的時間值,單位爲秒
cout << "test_mem_pool_perf_2: iter = " << iter << endl;
cout << "time: " << t << endl;
delete []p;
cout << "*********************test_mem_pool_perf_2*********************" << endl << endl << endl;
return t;
}
// 連續申請inner_iter次,釋放;重複iter/inner_iter次
double test_mem_pool_perf_3(PMEMORYPOOL mem_pool, int iter, int size)
{
cout << "*********************test_mem_pool_perf_3*********************" << endl;
int inner_iter = 10;
void **p = new void*[inner_iter];
if (p == NULL)
{
cout << "new faild" << endl;
return -1;
}
LARGE_INTEGER litmp;
LONGLONG QPart1, QPart2, start, finish;
double t;
double dfMinus, dfFreq;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 得到計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 得到初始值
for (int k = 0; k < iter / inner_iter; k++)
{
int j = 0;
for (j = 0; j < inner_iter; j++)
{
p[j] = GetMemory(size, mem_pool);
if (p[j] == NULL)
{
cout << "break @ iterator = " << j << " / " << iter << ", need memory " << size << " Byte" << endl;
cout << "total memory is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;
int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;
check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);
cout << "check memory pool result:" << endl;
cout << "free_chunk_count: " << free_chunk_count << endl
<< "total_free_mem: " << total_free_mem << endl
<< "max_chunk_size: " << max_chunk_size << endl
<< "min_chunk_size: " << min_chunk_size << endl;
break;
}
}
for (int i = 0; i < j; i++)
{
FreeMemory(p[i], mem_pool);
}
}
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//得到停止值
dfMinus = (double)(QPart2-QPart1);
t = dfMinus / dfFreq;// 得到對應的時間值,單位爲秒
cout << "test_mem_pool_perf_3: iter = " << iter << endl;
cout << "time: " << t << endl;
cout << "*********************test_mem_pool_perf_3*********************" << endl << endl << endl;
return t;
}
// 隨機內存大小,隨機釋放操做
double test_mem_pool_perf_rand(PMEMORYPOOL mem_pool, int iter, int* sizes, int* instruction)
{
cout << "-----------------------test_mem_pool_perf_rand----------------------- "<< endl;
void** p = new void*[iter];
if (p == NULL)
{
cout << "new failed" << endl;
return -1;
}
LARGE_INTEGER litmp, gftime;
LONGLONG QPart1, QPart2, start, finish;
double t, GetMemory_time, FreeMemory_time;
double dfMinus, dfFreq;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 得到計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 得到初始值
int index = 0;
int size;
int free_tmp = 0;
double seach_time;
for (int i = 0; i < iter; i++)
{
size = sizes[i];
p[index++] = GetMemory(size, mem_pool);
if (p[index-1] == NULL)
{
break_time++;
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;
cout << "total memory is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;
int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;
check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);
cout << "check memory pool result:" << endl;
cout << "free_chunk_count: " << free_chunk_count << endl
<< "total_free_mem: " << total_free_mem << endl
<< "max_chunk_size: " << max_chunk_size << endl
<< "min_chunk_size: " << min_chunk_size << endl;
break;
}
if (instruction[i] == 1)
{
FreeMemory(p[--index], mem_pool);
}
}
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//得到停止值
dfMinus = (double)(QPart2-QPart1);
t = dfMinus / dfFreq;// 得到對應的時間值,單位爲秒
cout << "test_mem_pool_perf_rand: iter = " << iter << endl;
cout << "time: " << t << endl << endl;
delete []p;
return t;
}
double test_std_perf(int iter, int* sizes, int* instruction)
{
cout << "test_std_perf" << endl;
void** p =new void*[iter];
if (p == NULL)
{
cout << "new failed" << endl;
return -1;
}
LARGE_INTEGER litmp;
LONGLONG QPart1, QPart2;
double t;
double dfMinus, dfFreq;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 得到計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 得到初始值
// cout << "test start" << endl;
int index = 0;
int size;
for (int i = 0; i < iter; i++)
{
size = sizes[i];
p[index++] = malloc(size);
if (p[index-1] == NULL)
{
cout << i << endl;
break;
}
if (instruction[i] == 1)
{
free(p[--index]);
}
}
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//得到停止值
dfMinus = (double)(QPart2-QPart1);
t = dfMinus / dfFreq;// 得到對應的時間值,單位爲秒
cout << "test_std_perf: iter = " << iter << endl;
cout << "time: " << t << endl << endl;
for (int k = 0; k < index; k++)
{
free(p[k]);
}
return t;
}
double test_std_perf_fix_size(int iter, int size)
{
cout << "******************* test_std_perf_fix_size *******************" << endl;
LARGE_INTEGER litmp;
LONGLONG QPart1, QPart2;
double t;
double dfMinus, dfFreq;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 得到計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 得到初始值
int index = 0;
for (int i = 0; i < iter; i++)
{
void *p = malloc(size);
if (p == NULL)
{
cout << i << endl;
break;
}
free(p);
}
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//得到停止值
dfMinus = (double)(QPart2-QPart1);
t = dfMinus / dfFreq;// 得到對應的時間值,單位爲秒
cout << "test_std_perf: iter = " << iter << endl;
cout << "time: " << t << endl;
cout << "******************* test_std_perf_fix_size *******************" << endl << endl << endl;
return t;
}
void test_correct_1(PMEMORYPOOL mem_pool, int iter, int size)
{
vector<void*>vec;
vector<void*>::iterator vec_iter;
int i = 0;
cout << "**************************** Get Memory Test Start ****************************"<< endl << endl;
for (i = 0; i < iter; i++)
{
void *p = GetMemory(size, mem_pool);
if (p == NULL)
{
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl << endl;
break;
}
vec.push_back(p);
}
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl << endl;
cout << "verify memory size" << endl;
memory_chunk* tmp = mem_pool->pfree_mem_chunk;
int free_size = 0;
for (int k = 0; k < mem_pool->free_mem_chunk_count; k++)
{
free_size += tmp->pfree_mem_addr->count * MINUNITSIZE;
tmp = tmp->next;
}
cout << "memory free size is " << free_size << " Byte" << endl;
cout << "memory used size is " << mem_pool->mem_used_size << " Byte" << endl;
cout << "*************************** Get Memory Test Finish ***************************"<< endl << endl;
cout << "*************************** Free Memory Test Start ***************************"<< endl << endl;
int index = 0;
for (vec_iter = vec.begin(); vec_iter != vec.end(); vec_iter++)
{
index++;
FreeMemory(*vec_iter, mem_pool);
}
cout << "memory left is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl << endl;
cout << "*************************** Free Memory Test Finish ***************************"<< endl << endl;
cout << "********************* Get Memory Test (after Free) Start *********************"<< endl << endl;
for (i = 0; i < iter; i++)
{
void *p = GetMemory(size, mem_pool);
if (p == NULL)
{
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl << endl;
int max_size = 0;
memory_chunk* tmp = mem_pool->pfree_mem_chunk;
for (int k = 0; k < mem_pool->free_mem_chunk_count; k++)
{
if (tmp->pfree_mem_addr->count * MINUNITSIZE > max_size)
{
max_size = tmp->pfree_mem_addr->count * MINUNITSIZE > max_size;
}
}
cout << "max chunk size is: " << max_size << " Byte" << endl;
break;
}
vec.push_back(p);
}
cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;
cout << "memory left is: " << mem_pool->size << " Byte" << endl;
cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl << endl;
cout << "verify memory size" << endl;
tmp = mem_pool->pfree_mem_chunk;
free_size = 0;
for (int k = 0; k < mem_pool->free_mem_chunk_count; k++)
{
free_size += tmp->pfree_mem_addr->count * MINUNITSIZE;
tmp = tmp->next;
}
cout << "memory free size is " << free_size << " Byte" << endl;
cout << "memory used size is " << mem_pool->mem_used_size << " Byte" << endl;
cout << "********************* Get Memory Test (after Free) Finish *********************"<< endl << endl;
}
/************************************************************************/
/* 內存池性能測試代碼
* 固定大小
/************************************************************************/
/*
void test_mem_pool_fix_size(PMEMORYPOOL mem_pool)
{
int iter = 200000;
int size = 512;
double t1 = test_std_perf_fix_size(iter, size);
double t2 = test_mem_pool_perf_1(mem_pool, iter, size);
double t3 = test_mem_pool_perf_2(mem_pool, iter, size);
double t4 = test_mem_pool_perf_3(mem_pool, iter, size);
cout << endl << endl
<< "test count: " << iter << ", test size: " << size << endl
<< "test result (system time / mem_pool time) : " << endl;
cout << "test_mem_pool_perf_1: " << t1 / t2 << endl
<< "test_mem_pool_perf_2: " << t1 / t3 << endl
<< "test_mem_pool_perf_3: " << t1 / t4 << endl;
}
*/
/************************************************************************/
/* 內存池性能測試代碼
* 隨機大小,隨機釋放操做
/************************************************************************/
void rand_test()
{
size_t sBufSize = 500* 1024*1024;
void*pBuf = malloc(sBufSize);
if (pBuf == NULL)
{
cout << "malloc failed" << endl;
return;
}
PMEMORYPOOL mem_pool = CreateMemoryPool(pBuf, sBufSize);
ofstream out("rand_test.txt");
int iter = 2000;
int* instruction = new int[iter];
int* sizes = new int[iter];
if (instruction == NULL || sizes == NULL)
{
cout << "new memory failed" << endl;
return;
}
srand(time(NULL));
cout << "generate rand number" << endl;
// instruction 中元素爲1時表示在GetMemory後執行FreeMemory,0表示不執行FreeMemory
// sizes中是每次分配內存的大小,範圍從64B~1024B
for (int i = 0; i < iter; i++)
{
instruction[i] = rand() % 2;
sizes[i] = (rand() % 16 + 1) * 64;
}
int test_count = 200;
double t1, t2;
double* ratio = new double[test_count];
int count = 0;
for (int k = 0; k < test_count; k++)
{
if (break_time != 0)
{
cout << "break @ " << k << " / " << test_count << endl;
break;
}
count++;
cout << "******************************************test " << k+1 << " *************************************************" << endl;
t1 = test_std_perf(iter, sizes, instruction);
t2 = test_mem_pool_perf_rand(mem_pool, iter, sizes, instruction);
cout << "total memory: " << mem_pool->size << ", memory used: " << mem_pool->mem_used_size
<< ", memory left: " << mem_pool->size - mem_pool->mem_used_size << endl;
ratio[k] = t1 / t2;
}
if(break_time == 0)
break_time = test_count;
break_time = count - 1;
cout << "*************************** ratio (system time / mem_pool time) ***************************" << endl;
for (int k = 0; k < break_time; k++)
{
out << ratio[k] << ",";
if (k % 10 == 0 && k != 0)
{
cout << endl;
}
cout << ratio[k] << " ";
}
cout << endl;
delete []ratio;
delete []instruction;
delete []sizes;
free(pBuf);
}
// 申請緊接着釋放
void rand_test_2()
{
size_t sBufSize = 500* 1024*1024;
void*pBuf = malloc(sBufSize);
if (pBuf == NULL)
{
cout << "malloc failed" << endl;
return;
}
PMEMORYPOOL mem_pool = CreateMemoryPool(pBuf, sBufSize);
int iter = 2000;
int test_count = 511;
int* sizes = new int[iter];
double* ratio = new double[test_count];
if (sizes == NULL || ratio == NULL)
{
cout << "new memory failed" << endl;
return;
}
srand(time(NULL));
cout << "generate rand number" << endl;
ofstream out("rand_test_2.txt");
for (int k = 0; k < test_count; k++)
{
for (int i = 0; i < iter; i++)
{
sizes[i] = (rand() % 16 + 1) * 64 + 1024 * k;
}
double mem_pool_t = test_mem_pool_perf_1(mem_pool, iter, sizes);
double std_t = test_std_perf_1(iter, sizes);
ratio[k] = std_t / mem_pool_t;
}
cout << "*************************** ratio (system time / mem_pool time) ***************************" << endl;
for (int k = 0; k < test_count; k++)
{
out << ratio[k] << ",";
if (k % 10 == 0 && k != 0)
{
cout << endl;
}
cout << ratio[k] << " ";
}
cout << endl;
delete []sizes;
delete ratio;
free(pBuf);
}
int _tmain(int argc, _TCHAR* argv[])
{
rand_test();
// rand_test_2();
return 0;
}