相对于在栈空间分配内存,堆中分配内存其实是非常缓慢的。
另外,由于堆中分配的内存,需要开发者编码回收,当系统非常庞大时,容易出现分配的内容没有回收导致内存泄露的现象。
因此,许多Bible建议开发者尽量使用栈空间,少用甚至不用malloc和free、new和delete;
虽然栈的空间较小,但这样的建议随着计算机的位数从32位升级到64位,越来越成为真理。
但我还是想说,这是有限制的:那就是这条真理适用于多线程程序,但在多协程程序中,由于协程栈空间的限制,极容易撑爆协程栈。
为了提高堆分配内存的速度,内存池出现了。
相关阅读
----经典的内存池技术
下面提供固定大小的内存池和可变大小的内存池实现。经过测试,它的性能远高于Boost的内存池哦!
头文件base.h
#ifndef __PP_BASE_H__
#define __PP_BASE_H__
#if (defined(WIN32) || defined(WIN64))
#ifndef WINVER // Specifies that the minimum required platform is Windows Vista.
#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif
#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0.
#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE.
#endif
//////////////////////////////////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <winsock2.h>
#include <windows.h>
#ifndef PPAPI
#define PPAPI __stdcall
#endif
#else
#ifndef PPAPI
#define PPAPI
#endif
#endif
#endif
内存池cpp文件
#include "memorypool.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
CVarMemoryPool::CVarMemoryPool()
:m_pHeadPage(NULL), m_pWorkPage(NULL), m_pPageBuf(NULL)
{
for (unsigned int i = 0; i < UNIT_TYPE_COUNT; ++ i)
{
m_pFreeHead[i] = NULL;
m_nFreeCount[i] = 0;
}
}
CVarMemoryPool::~CVarMemoryPool()
{
MemoryPage* pMemoryPage = m_pHeadPage;
while (m_pHeadPage != NULL)
{
pMemoryPage = m_pHeadPage->Next;
free(m_pHeadPage);
m_pHeadPage = pMemoryPage;
}
}
void* CVarMemoryPool::Malloc(unsigned int Len)
{
assert(Len > 0);
Len ++;
if (Len > MAX_UNIT_SIZE)
{
// allocate memory from system if requery Len is too large
void* buf = malloc(Len);
if (buf == NULL)
{
return NULL;
}
//if content of 1 byte before memory means allocate form system
*(char*)buf = 0;
return (char*)buf + 1;
}
else
{
return GetPoolMemory(Len);
}
}
void CVarMemoryPool::Free(void* p)
{
assert(p != NULL);
char* temp = (char*)p - 1;
unsigned char type = *temp;
if (type == 0) //if content of 1 byte before memory means allocate form system
{
free(temp);
}
else
{
FreePoolMemory(temp, type);
}
}
void* CVarMemoryPool::GetPoolMemory(unsigned int Len)
{
Len = (Len + (ALIGNMENT-1)) & ~(ALIGNMENT-1);
int idx = (Len - 1) / ALIGNMENT;
//if free memory unit is not enough, first get some free units
if (m_nFreeCount[idx] == 0
&& !AddFreeMemory(idx))
{
return NULL;
}
-- m_nFreeCount[idx];
char* buf = m_pFreeHead[idx];
m_pFreeHead[idx] = (char*)(*((INT64*)m_pFreeHead[idx]));
*buf = idx + 1;
return buf + 1;
}
void CVarMemoryPool::FreePoolMemory(void* memblock, unsigned char type)
{
int idx = type - 1;
*(INT64*)memblock = (INT64)m_pFreeHead[idx];
m_pFreeHead[idx] = (char*)memblock;
++ m_nFreeCount[idx];
}
bool CVarMemoryPool::AddFreeMemory(int idx)
{
const int UNIT_SIZE = (idx + 1) * ALIGNMENT;
if ((m_pPageBuf + UNIT_SIZE ) > GetPageBufEnd(m_pWorkPage)
&& !SetMemoryPage())
{
return false;
}
char* page_end = GetPageBufEnd(m_pWorkPage);
for (unsigned int i = 0; i < ALLOC_COUNT; ++ i)
{
*(INT64*)m_pPageBuf = (INT64)m_pFreeHead[idx];
m_pFreeHead[idx] = m_pPageBuf;
m_pPageBuf += UNIT_SIZE;
++ m_nFreeCount[idx];
if (m_pPageBuf + UNIT_SIZE > page_end)
break;
}
return true;
}
bool CVarMemoryPool::SetMemoryPage()
{
if(m_pWorkPage->Next != NULL)
{
m_pWorkPage = m_pWorkPage->Next;
}
else
{
void* buf = malloc(sizeof(MemoryPage) + m_nPageSize);
if (buf == NULL)
{
return false;
}
else
{
MemoryPage* pMemoryPage = (MemoryPage*)(buf);
pMemoryPage->Next = NULL;
m_pWorkPage->Next = pMemoryPage;
m_pWorkPage = pMemoryPage;
}
}
m_pPageBuf = GetPageBufGegin(m_pWorkPage);
return true;
}
int CVarMemoryPool::GetMemUsed()
{
int used = 0;
const int PAGE_SIZE = sizeof(MemoryPage) + m_nPageSize;
MemoryPage* pMemoryPage = m_pHeadPage;
while (pMemoryPage != NULL)
{
pMemoryPage = pMemoryPage->Next;
used += PAGE_SIZE;
}
return used;
}
void CVarMemoryPool::Clear()
{
m_pWorkPage = m_pHeadPage;
m_pPageBuf = GetPageBufGegin(m_pWorkPage);
}
bool CVarMemoryPool::Create( unsigned int PageSize /*= 0x80000*/ )
{
PageSize = (PageSize + (ALIGNMENT-1)) & ~(ALIGNMENT-1);
if (PageSize < MIN_PAGESIZE)
{
m_nPageSize = MIN_PAGESIZE;
}
else
{
m_nPageSize = PageSize;
}
void* buf = malloc(sizeof(MemoryPage) + m_nPageSize);
if (buf == NULL)
{
return false;
}
else
{
MemoryPage* pMemoryPage = (MemoryPage*)(buf);
pMemoryPage->Next = NULL;
m_pWorkPage = pMemoryPage;
m_pPageBuf = GetPageBufGegin(m_pWorkPage);
m_pHeadPage = m_pWorkPage;
}
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
CFixMemoryPool::CFixMemoryPool()
:m_pHeadPage(NULL), m_nUnitSize(0), m_nPageSize(0)
{
}
CFixMemoryPool::~CFixMemoryPool()
{
MemoryPage* pMemoryPage = m_pHeadPage;
while (m_pHeadPage != NULL)
{
pMemoryPage = m_pHeadPage->Next;
free(m_pHeadPage);
m_pHeadPage = pMemoryPage;
}
}
void* CFixMemoryPool::Malloc()
{
MemoryPage* pMemoryPage = m_pHeadPage;
while (pMemoryPage != NULL && pMemoryPage->nFreecount == 0)
{
pMemoryPage = pMemoryPage->Next;
}
// add new page if space is not enough
if (pMemoryPage == NULL)
{
if(!AddMemoryPage())
{
return NULL;
}
pMemoryPage = m_pHeadPage;
}
// get unused memory
-- pMemoryPage->nFreecount;
char* buf = GetPageBuf(pMemoryPage) + pMemoryPage->nFreeHead * m_nUnitSize;
pMemoryPage->nFreeHead = *(int*)(buf);
return buf;
}
void CFixMemoryPool::Free(void* p)
{
// don't check null point for fast
MemoryPage* pMemoryPage = m_pHeadPage;
char* buf = GetPageBuf(m_pHeadPage);
// find point in which page
while((p < buf ||
p > buf + m_nPageSize) &&
pMemoryPage != NULL)
{
pMemoryPage = pMemoryPage->Next;
buf = GetPageBuf(pMemoryPage);
}
// do not in any page
if (pMemoryPage == NULL)
{
return;
}
*(int*)p = pMemoryPage->nFreeHead;
pMemoryPage->nFreeHead = ((char*)p - buf) / m_nUnitSize;
++ pMemoryPage->nFreecount;
return;
}
bool CFixMemoryPool::AddMemoryPage()
{
void* buf = malloc(sizeof(MemoryPage) + m_nPageSize);
if (buf == NULL)
{
return false;
}
MemoryPage* pMemoryPage = (MemoryPage*)(buf);
InitPage(pMemoryPage);
if (m_pHeadPage == NULL)
{
pMemoryPage->Next = NULL;
m_pHeadPage = pMemoryPage;
}
else
{
pMemoryPage->Next = m_pHeadPage;
m_pHeadPage = pMemoryPage;
}
return true;
}
int CFixMemoryPool::GetMemUsed()
{
int used = 0;
const int PAGE_SIZE = sizeof(MemoryPage) + m_nPageSize;
MemoryPage* pMemoryPage = m_pHeadPage;
while (pMemoryPage != NULL)
{
pMemoryPage = pMemoryPage->Next;
used += PAGE_SIZE;
}
return used;
}
void CFixMemoryPool::Clear()
{
MemoryPage* pMemoryPage = m_pHeadPage;
while (pMemoryPage != NULL)
{
InitPage(pMemoryPage);
pMemoryPage = pMemoryPage->Next;
}
}
void CFixMemoryPool::InitPage(MemoryPage *Page)
{
Page->nFreecount = m_nPageSize / m_nUnitSize;
Page->nFreeHead = 0;
void* head = GetPageBuf(Page);
for (int i = 1; i < Page->nFreecount; ++i)
{
*(int*)head = i;
head = (int*)((char*)head + m_nUnitSize);
}
}
bool CFixMemoryPool::Create( unsigned int UnitSize, unsigned int PageSize /*= 0x40000*/ )
{
if (UnitSize < 4)
{
m_nUnitSize = 4;
}
{
m_nUnitSize = (UnitSize + (ALIGNMENT-1)) & ~(ALIGNMENT-1);
}
if (PageSize < MIN_PAGESIZE)
{
m_nPageSize = MIN_PAGESIZE;
}
else
{
m_nPageSize = (PageSize / m_nUnitSize) * m_nUnitSize;
}
return AddMemoryPage();
}