明天回家了~~~~
今天放上一个内存池的实现,该内存池基于之前发的单链表和双链表。并且参考了Apache内存池的实现。
PS
2013.2.21修改:
将之前的单链表管理的分配子改为AVL树管理
2013.3.1修改:
因为AVL树的结点结构有做修改
内存池也做了相关功能的修改。
主要是内存池分配子的查找操作,bool operator <=(const CMemoryAllocator &t);也去掉不用。
增加了一个函数DWORD GetKey();返回对象的键值
2013.6.26修改:
针对容器的修改,做相关调用的调整
先讲下这个内存池的大致实现方法:
1、该内存池(CMemoryPool)其下管理若干个内存分配子(CMemoryAllocator)。
每个内存分配子管理初始化时分配的那块大内存,以及每次内存不够而新增的大内存,每块大内存对应一个内存分配子。
2、两个定义:
(1)、元内存块:
按照内存池的最小分配粒度(dwUnitSize)大小为基本单位
一个dwUnitSize大小的内存块即为一个元内存块,
一个元内存块对应由一个内存管理结点(CMemLinker)管理
(2)、原子内存块
若干个物理地址连续的元内存块可以合并在一起组成原子内存块
原子内存块用以满足上层逻辑对不同大小的内存的逻辑需求
当元内存块合并在一起组成原子内存块时
只有原子内存块的第一个元内存块对应的管理结点(CMemLinker)被链入使用列表或者空闲链表
3、该内存池有两个重要属性:最小分配粒度(dwUnitSize)与最大分配粒度(dwMaxUnitSize)。
举例说明最小分配粒度为128B,最大分配粒度4KB,那么:
当逻辑需要的一块内存大于最大分配粒度(4KB),内存池将分配失败
当逻辑需要的一块内存小于最大分配粒度时,内存池将分配一个大小为最小分配粒度(128B)的整数倍,且值最小的内存给上层逻辑使用
如当逻辑需要的一块内存<=128B时,内存池将分配一个大小128B的内存给上层逻辑使用
当需要3000B时,分配的内存大小为((3000 - 1) / 最小分配粒度 + 1)*最小分配粒度 = 3072B。
最小分配粒度与最大分配粒度需要在内存池初始化的时候,上层逻辑作为初始化参数指定大小。
4、根据最小分配粒度与最大分配粒度,内存池的空闲内存链表,将分为level=(最大分配粒度/最小分配粒度 + 1)个级别。
其中free[0]对应超过最大分配粒度的内存块,free[1]到free[level]分别对应分配粒度从1倍到level倍大小的内存块。
当上层逻辑需要一块内存时,优先从合适的空闲列表中分配,不够再向更高级别的空闲列表分配。
举例说明:当逻辑需要3000B,计算出来合适的分配大小为3072B,处于free[24]这个级别的空闲列表,则优先从这个列表中取一个空闲内存。
若这个列表当前没有空闲内存了,向上找free[25],也没有空闲内存,找free[26],有空闲内存了,分配一个。
此时由于free[26]上的内存要比3072B大两个级别(即大256B)的,那么从free[26]上申请的这个内存块将截断为3072B的一块内存,以及256B的一块小内存。
这块256B的小内存是最小分配粒度(128B)的2倍,因此这块多余的小内存将放入free[2]这块空闲列表中备用。
5、使用中列表used,内存池中的使用中列表只有一个。
无论分配出的多大的内存块,都将被链入这个链表中,不做大小区分
6、内存池内存不够时的分配策略:两种
(1)、增加一块新内存(即增加一个内存分配子);
(2)、合并零散内存块,若合并之后依然不够,再执行增加新内存块的操作
(因为当需要合并时,说明从所需内存块级别往上都已经没有合适的内存块可以用了)
①、从free[n-1]取一块空闲内存Buff。
②、判断其下一块物理地址连续的原子内存块(其定义在第一点中)是否是空闲的内存块。
③、是则合并,得到一个新的级别大小newlevel,放入free[newlevel]。不是则取free[n-1]的第二块空闲内存继续操作②
④、若newlevel依然大小不够逻辑需要,再取此时新的Buff的下一块原子内存块,若空闲进行合并。
⑤、若Buff下一块原子内存块不是空闲内存,则取free[n-1]的第二块空闲内存继续操作②。
⑥、直到某次合并操作成功合并出一块大小合适的内存块为止。
7、释放内存时,暂时有个不是很理想的情况,就是因为上层逻辑给的参数为char *pBuff,上层逻辑也只知道这个pBuff。
内存池需要根据pBuff的地址,逐个判断下这个地址是属于哪个内存池分配子分配的内存。
然后计算出这个pBuff的管理结点。
有一步遍历每个内存池分配子的操作在里面。当内存池分配了很多个内存池分配子的情况下,遍历还是需要时间的。
因此暂时需要在使用内存池时,预估逻辑大致需要多大的总内存,防止内存池频繁的进行申请新的内存池分配子的操作。
后面在考虑将这个管理内存池分配子的链表换成TTree,节省搜索的时间。(2013.2.21已修改)
8、下图显示5个空闲级别,最小分配粒度128B,3个内存分配子的情况下,内存管理情况
(没有加使用中列表used,used在内存池中只有一个)
1、内存池分配子:CMemoryAllocator.h
#ifndef _CMemoryAllocator_h_
#define _CMemoryAllocator_h_
#include <windows.h>
#include <stdio.h>
#include "TBDLinkList.h"
//内存池分配子
class CMemoryAllocator;
//内存池的元内存块管理结点
//定义:
//1、元内存块:
// 按照内存池的dwUnitSize大小为基本单位
// 一个dwUnitSize大小的内存块即为一个元内存块,
// 一个元内存块对应由一个CMemLinker管理
//2、原子内存块
// 若干个物理地址连续的元内存块可以合并在一起组成原子内存块
// 原子内存块用以满足上层逻辑对不同大小的内存的逻辑需求
// 当元内存块合并在一起组成原子内存块时
// 只有原子内存块的第一个元内存块对应的管理结点CMemLinker被链入使用列表或者空闲链表
struct CMemLinker
{
CMemoryAllocator *m_pMemAlloc; //该结点所属内存池分配子
//用于零散原子内存块合并时获取其所属分配子对象
//以及判断两个原子内存块是否属于同一个分配子
//不属于同一分配子的内存默认为不连续,不可以合并分配
DWORD m_dwCount; //原子内存块 管理的 元内存块 的个数
//dwCount是在被上层逻辑申请内存时被赋值
//dwCount==0表示其管理的那块元内存块不是原子内存块的第一个
char *pData; //该结点管理的元内存块首地址
};
//内存池分配子
// 申请内存池需要的大块内存
// 将其按dwUnitSize大小划分元内存块
// 分配内存管理结点CMemLinker来管理这些元内存块
// 申请的大块内存和内存管理结点由分配子自己负责释放
class CMemoryAllocator
{
public:
CMemoryAllocator();
~CMemoryAllocator();
//申请连续的大块内存,并为其创建内存管理结点
//dwBuffSize: 大块内存的大小
//dwUnitSize: 内存池的分配粒度,分配子按照该大小将大块内存分割成元内存块
//list: 被分配出来的初始内存块需要被放入的内存块链表管理器
//dwBuffSize 必须为 dwUnitSize 的整数倍
public:
bool Init(DWORD dwBuffSize, DWORD dwUnitSize, TBDLinkList<CMemLinker> &list);
//释放申请的大块内存,释放内存管理结点
public:
void Release();
//根据元内存块地址,计算指向该数据块的管理结点
//返回该结点
//pBuff不属于当前分配子所管理的内存范围,返回NULL
//ps:如果pBuff不是元内存块的首地址,将返回正确结果
public:
TBDLinker<CMemLinker> *GetBuffLinker(const char * const pBuff);
//计算pLinker物理地址连续的下一个原子结点 理论上的位置
//该函数不检查参数合法性
//没有下一个原子结点返回NULL
public:
TBDLinker<CMemLinker> *GetNextAtomicity(const TBDLinker<CMemLinker> * const pLinker);
//由于分配子用AVL树来管理
//这里提供2个比较函数函数
//以及获取关键字的函数
public:
char *GetKey();
bool operator==(const char *k);
bool operator>(const char *k);
//内存统计
public:
DWORD GetAllocatorSize();
private:
TBDLinker<CMemLinker> *m_pHead; //链表管理结点头指针
char *m_pDataBuff; //所管理的整内存块
char *m_pEndDataBuff; //所管理的m_pDataBuff结束地址
DWORD m_dwBuffSize; //内存总大小
DWORD m_dwUnitSize; //分配内存时的分配粒度 即一个一个元内存块大小
};
#endif
CMemoryAllocator.cpp
#include "CMemoryAllocator.h"
CMemoryAllocator::CMemoryAllocator()
{
m_pDataBuff = NULL;
m_pEndDataBuff = NULL;
m_dwBuffSize = 0;
m_dwUnitSize = 0;
m_pHead = NULL;
}
CMemoryAllocator::~CMemoryAllocator()
{
Release();
}
bool CMemoryAllocator::Init(DWORD dwBuffSize, DWORD dwUnitSize, TBDLinkList<CMemLinker> &list)
{
if (NULL != m_pHead || NULL != m_pDataBuff)
{
//该对象现已有所管理的内存,不可以初始化
return false;
}
else if (0 == dwBuffSize || 0 == dwUnitSize)
{
//初始化参数不正确
return false;
}
else if (0 != dwBuffSize % dwUnitSize)
{
//总大小 无法由 整数个分配粒度合并
return false;
}
else
{
//分配内存
m_pDataBuff = new char[dwBuffSize];
if (NULL == m_pDataBuff)
{
return false;
}
m_pEndDataBuff = m_pDataBuff + dwBuffSize - 1;
m_dwBuffSize = dwBuffSize;
m_dwUnitSize = dwUnitSize;
//分配内存管理结点
//每个结点管理一个元内存块
DWORD dwLinkerCount = m_dwBuffSize / m_dwUnitSize;
m_pHead = new TBDLinker<CMemLinker>[dwLinkerCount];
if (NULL == m_pHead)
{
delete[] m_pDataBuff;
m_pDataBuff = NULL;
return false;
}
DWORD i = 0;
for (i = 0; i < dwLinkerCount; i++)
{
m_pHead[i].m_pLast = NULL;
m_pHead[i].m_pNext = NULL;
m_pHead[i].m_pLinkList = NULL;
m_pHead[i].m_Value.m_pMemAlloc = this;
m_pHead[i].m_Value.m_dwCount = 0;
m_pHead[i].m_Value.pData = m_pDataBuff + i * dwUnitSize;
}
//将整块内存作为原子结点放入空闲列表
m_pHead[0].m_Value.m_dwCount = dwLinkerCount;
list.PushTail(m_pHead);
return true;
}
}
void CMemoryAllocator::Release()
{
if (NULL != m_pDataBuff)
{
delete[] m_pDataBuff;
m_pDataBuff = NULL;
m_pEndDataBuff = NULL;
m_dwBuffSize = 0;
m_dwUnitSize = 0;
}
if (NULL != m_pHead)
{
delete[] m_pHead;
m_pHead = NULL;
}
}
TBDLinker<CMemLinker> *CMemoryAllocator::GetBuffLinker(const char * const pBuff)
{
if (m_pDataBuff <= pBuff && pBuff <= m_pEndDataBuff)
{
__int64 dwIndex = (pBuff - m_pDataBuff) / m_dwUnitSize;
return m_pHead + dwIndex;
}
else
{
return NULL;
}
}
TBDLinker<CMemLinker> *CMemoryAllocator::GetNextAtomicity(const TBDLinker<CMemLinker> * const pLinker)
{
char *pCurrBuff = pLinker->m_Value.pData;
char *pNextBuff = pCurrBuff + m_dwUnitSize * pLinker->m_Value.m_dwCount;
TBDLinker<CMemLinker> *pNextLinker = GetBuffLinker(pNextBuff);
if (NULL != pNextLinker && 0 != pNextLinker->m_Value.m_dwCount)
{
return pNextLinker;
}
else
{
return NULL;
}
}
char *CMemoryAllocator::GetKey()
{
return m_pDataBuff;
}
bool CMemoryAllocator::operator==(const char *k)
{
if (m_pDataBuff <= k && k <= m_pEndDataBuff)
{
return true;
}
else
{
return false;
}
}
bool CMemoryAllocator::operator>(const char *k)
{
if (m_pDataBuff > k)
{
return true;
}
else
{
return false;
}
}
DWORD CMemoryAllocator::GetAllocatorSize()
{
return m_dwBuffSize;
}
2、内存池:CMemoryPool.h
#ifndef _CMemoryPool_h_
#define _CMemoryPool_h_
#include <windows.h>
#include "TBDLinkList.h"
#include "TTree.h"
#include "CMemoryAllocator.h"
#include "CLock.h"
enum MemPoolFlag
{
enum_AddMemory = 0, //分配策略为速度优先,内存不够时开辟新内存
enum_JoinMemory, //内存不够时尝试合并小内存块,之后依然无合适的内存可以分配再开辟新内存
};
//内存池
// 该类自己负责申请、释放内存分配子
// 对内存块链表化,并管理它的使用情况
// 当内存不够时,整理合并零散内存,或开辟新的内存块
// 适用于变长大小的内存需求
//
//根据逻辑实际需要内存的大小,分配连续的1个或多个元内存块组成最接近的内存大小
//
//该管理器由多个列表组成:
// 使用中列表1个
// 空闲列表m_nLevel+1个
// m_pFree[0]对应超过dwMaxUnitSize(超过m_nLevel*m_dwUnitSize)的内存块
// m_pFree[1]到m_pFree[m_nLevel]分别对应分配粒度从1倍到m_nLevel倍大小的内存块
// 内存分配子列表1个
class CMemoryPool
{
public:
CMemoryPool();
~CMemoryPool();
//初始化内存池
//dwFirstBuffSize: 初次开辟的大块内存的大小
//dwAddBuffSize: 内存池内存不够,需要重新开辟内存时,每次开辟的内存大小
// 为0时表示永不开辟新内存,内存不够时返回申请失败
//dwUnitSize: 分配内存时的分配粒度,也即最小分配大小
//dwMaxUnitSize: 分配内存时的最大分配大小
//dwMallocType: 内存池内存不够时的策略,是否尝试合并小内存
//dwLock: 设置是否使用临界区
//
//dwFirstBuffSize与dwAddBuffSize 必须为 dwUnitSize 的整数倍 且大于dwMaxUnitSize
//dwMaxUnitSize 必须为 dwUnitSize 的整数倍
public:
bool Init(DWORD dwFirstBuffSize,
DWORD dwAddBuffSize,
DWORD dwUnitSize = 256,
DWORD dwMaxUnitSize = 4096,
MemPoolFlag dwMallocType = enum_AddMemory,
ContainerFlag dwLock = enum_EnableLock);
//释放对象池的所有分配子及其内存
public:
void Release();
//从指定空闲列表得到物理连续的若干个空闲元内存块管理结点
//返回获取到的结点所管理的那块内存首地址
//当指定空闲列表不够分配时返回NULL
//dwIndex:指定空闲列表编号,范围0到m_nLevel
//n:要获取的连续空闲元内存管理结点个数,范围1到m_nLevel
private:
char *MallocFromFree(DWORD dwIndex, DWORD n);
//增加分配子,开辟新内存
//成功返回true
//失败返回false
//dwAddSize:要增加的内存分配子的大小
private:
bool AddMemory(DWORD dwAddSize);
//合并零散内存块,直到足够分配连续的n个可用内存管理结点为止
//n: 要合并的连续可用元内存管理结点个数,n>=2
// 若n=1,则其无法再由更小的元内存块合并
// 若n=0,不符合逻辑
//返回-1,表示进行所有可能的合并之后,依然没有合适的内存块可以使用
//返回0到m_nLevel,表示合并之后,该合适大小的内存块处于哪个空闲链表上(它的下标)
private:
DWORD JoinMemory(DWORD n);
//从空闲列表得到一个大小适合的原子结点,放入使用列表中
//返回获取到的结点所管理的那块内存,当没有空闲结点时返回NULL
public:
char *Malloc(DWORD dwSize);
char *MallocMinSize();
char *MallocMaxSize();
//将指定结点从使用列表放入对应空闲列表,当该结点不合法时返回false
//pBuff: 该结点对应的内存块,即CMemLinker中的pData
// 上层逻辑不需要知道其操作的某个数据在管理器中对应的管理结点是谁
// 管理器自己判断该数据是否属于自己管理的数据块
// 以及该数据块是由哪个结点管理的
public:
bool Free(const char *pBuff);
//内存统计
public:
DWORD GetPoolSize();
DWORD GetUseSize();
private:
TBDLinkList<CMemLinker> m_Used;//使用中列表(管理的是原子)
TBDLinkList<CMemLinker> *m_pFree;//空闲列表数组(管理的是原子)
DWORD m_dwLevel;//分配粒度等级,即空闲列表个数(不包括下标0的那个空闲列表)
TTree<char *, CMemoryAllocator> m_MemAllocList;//内存池分配子管理树
DWORD m_dwFirstBuffSize;//初次开辟的大块内存的大小
DWORD m_dwAddBuffSize;//内存池内存不够,需要重新开辟内存时,每次开辟的内存大小
DWORD m_dwUnitSize;//分配内存时的分配粒度,也即最小分配大小
DWORD m_dwMaxUnitSize;//分配内存时的最大分配大小
MemPoolFlag m_dwMallocType;//内存池内存不够时的策略,是否尝试合并小内存
CLock m_csLock; //临界区,保证池操作的线程安全
ContainerFlag m_dwLock; //是否使用临界区进行加锁
DWORD m_dwPoolSize; //内存池当前管理的总内存大小
DWORD m_dwUseSize; //内存池当前被使用的内存大小
};
#endif
CMemoryPool.cpp文件
#include "CMemoryPool.h"
#include "tool.h"
CMemoryPool::CMemoryPool()
{
m_Used.Init(enum_DisableLock);
m_pFree = NULL;
m_dwLevel = 0;
m_MemAllocList.Init(enum_DisableLock);
m_dwFirstBuffSize = 0;
m_dwAddBuffSize = 0;
m_dwUnitSize = 0;
m_dwMaxUnitSize = 0;
m_dwMallocType = enum_AddMemory;
m_dwLock = enum_EnableLock;
m_dwPoolSize = 0;
m_dwUseSize = 0;
}
CMemoryPool::~CMemoryPool()
{
Release();
}
bool CMemoryPool::Init(DWORD dwFirstBuffSize,
DWORD dwAddBuffSize,
DWORD dwUnitSize,
DWORD dwMaxUnitSize,
MemPoolFlag dwMallocType,
ContainerFlag dwLock)
{
if (0 == dwFirstBuffSize || 0 == dwUnitSize || 0 == dwMaxUnitSize)
{
//初始化参数不正确
return false;
}
else if (0 != dwFirstBuffSize % dwUnitSize || 0 != dwAddBuffSize % dwUnitSize)
{
//总大小 无法由 整数个分配粒度合并
return false;
}
else if (0 != dwMaxUnitSize % dwUnitSize)
{
//最大分配粒度 无法由 整数个分配粒度合并
return false;
}
else
{
Release();
m_dwFirstBuffSize = dwFirstBuffSize;
m_dwAddBuffSize = dwAddBuffSize;
m_dwUnitSize = dwUnitSize;
m_dwMaxUnitSize = dwMaxUnitSize;
m_dwMallocType = dwMallocType;
m_dwLock = dwLock;
m_dwLevel = dwMaxUnitSize / dwUnitSize;
m_pFree = new TBDLinkList<CMemLinker>[m_dwLevel + 1];
if (NULL == m_pFree)
{
return false;
}
for (DWORD i = 0; i <= m_dwLevel; i++)
{
m_pFree[i].Init(enum_DisableLock);
}
//申请分配子,开辟第一块内存
//将初始内存块挂入0号空闲列表
return AddMemory(dwFirstBuffSize);
}
}
void CMemoryPool::Release()
{
m_Used.Init(enum_DisableLock);
if (NULL != m_pFree)
{
for (DWORD i = 0; i <= m_dwLevel; i++)
{
m_pFree[i].Init(enum_DisableLock);
}
delete[] m_pFree;
m_pFree = NULL;
}
m_dwLevel = 0;
TLeaf<char *, CMemoryAllocator> *pLeaf = m_MemAllocList.RemoveHead();
while (NULL != pLeaf)
{
delete pLeaf;
pLeaf = m_MemAllocList.RemoveHead();
}
m_MemAllocList.Init(enum_DisableLock);
m_dwFirstBuffSize = 0;
m_dwAddBuffSize = 0;
m_dwUnitSize = 0;
m_dwMaxUnitSize = 0;
m_dwMallocType = enum_AddMemory;
m_dwLock = enum_EnableLock;
m_dwPoolSize = 0;
m_dwUseSize = 0;
}
char *CMemoryPool::MallocMinSize()
{
return Malloc(m_dwUnitSize);
}
char *CMemoryPool::MallocMaxSize()
{
return Malloc(m_dwMaxUnitSize);
}
char *CMemoryPool::Malloc(DWORD dwSize)
{
if (dwSize < 1 || m_dwMaxUnitSize < dwSize)
{
return NULL;
}
//待返回的申请到的内存地址
char *pBuff = NULL;
//逻辑需要的dwSize大小的内存需要几个元内存块组成
DWORD n = (dwSize - 1) / m_dwUnitSize + 1;
DWORD nSize = n * m_dwUnitSize;
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
//优先从超过m_dwMaxUnitSize列表m_pFree[0]中分配内存
//若m_pFree[0]已经使用完了,按[n]到[m_dwLevel]的列表顺序寻找合适内存块
pBuff = MallocFromFree(0, n);
if (NULL != pBuff)
{
m_dwUseSize += nSize;
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pBuff;
}
for (DWORD i = n; i <= m_dwLevel; i++)
{
pBuff = MallocFromFree(i, n);
if (NULL != pBuff)
{
m_dwUseSize += nSize;
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pBuff;
}
}
//无法分配内存 增加分配子或合并零散内存
if (enum_JoinMemory == m_dwMallocType)
{
DWORD dwIndex = JoinMemory(n);
if (0 <= dwIndex && dwIndex <= m_dwLevel)
{
pBuff = MallocFromFree(dwIndex, n);
m_dwUseSize += nSize;
//此时因为理论上m_pFree[nIndex]必定会有合适大小的内存
//因此不再判断pBuff是否为空
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pBuff;
}
}
if (AddMemory(m_dwAddBuffSize))
{
pBuff = MallocFromFree(0, n);
m_dwUseSize += nSize;
//此时因为理论上m_pFree[0]必定会有合适大小的内存
//因此不再判断pBuff是否为空
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pBuff;
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return NULL;
}
char *CMemoryPool::MallocFromFree(DWORD dwIndex, DWORD n)
{
TBDLinker<CMemLinker> *pLinker = NULL;
CMemLinker *pMemLinker = m_pFree[dwIndex].GetHead();
pLinker = (TBDLinker<CMemLinker> *)m_pFree[dwIndex].GetNode(pMemLinker);
if (NULL != pLinker)
{
if (n <= pLinker->m_Value.m_dwCount)
{
//pLinker所对应的原子内存块足够分配n个元内存块
//从该空闲列表删除该结点
m_pFree[dwIndex].Remove(pLinker);
//记算pLinker分配n个元内存块之后是否有剩余
if (n < pLinker->m_Value.m_dwCount)
{
TBDLinker<CMemLinker> *pSurplusLinker = pLinker + n;
pSurplusLinker->m_Value.m_dwCount = pLinker->m_Value.m_dwCount - n;
pLinker->m_Value.m_dwCount = n;
if (m_dwLevel < pSurplusLinker->m_Value.m_dwCount)
{
m_pFree[0].PushTail(pSurplusLinker);
}
else
{
m_pFree[pSurplusLinker->m_Value.m_dwCount].PushTail(pSurplusLinker);
}
}
m_Used.PushTail(pLinker);
return pLinker->m_Value.pData;
}
else
{
//该空闲列表的原子内存块不足以分配所需大小的内存块
return NULL;
}
}
else
{
//空闲列表没有可分配内存
return NULL;
}
}
bool CMemoryPool::AddMemory(DWORD dwAddSize)
{
if (0 == dwAddSize)
{
return false;
}
//申请分配子,开辟新内存
TLeaf<char *, CMemoryAllocator> *pAllocLinker = new TLeaf<char *, CMemoryAllocator>;
if (NULL == pAllocLinker)
{
return false;
}
pAllocLinker->Init();
if (!pAllocLinker->m_Value.Init(dwAddSize, m_dwUnitSize, m_pFree[0]))
{
delete pAllocLinker;
return false;
}
pAllocLinker->m_Key = pAllocLinker->m_Value.GetKey();
if (!m_MemAllocList.Insert(pAllocLinker))
{
delete pAllocLinker;
return false;
}
m_dwPoolSize += dwAddSize;
return true;
}
DWORD CMemoryPool::JoinMemory(DWORD n)
{
if (n < 2)
{
//小于2块元内存无法合并
return 0xffffffff;
}
//待合并的结点
TBDLinker<CMemLinker> *pLinker = NULL;
//pLinker合并之后,若依然不符合大小要求情况下,下一个待合并的结点
TBDLinker<CMemLinker> *pNextLinker = NULL;
//pLinker物理地址连续的下一个原子结点
TBDLinker<CMemLinker> *pNextAtomicity = NULL;
for (DWORD i = n - 1; i > 0; i--)//从大内存向小内存合并,为了更快的分配出适合的内存
{
pLinker = (TBDLinker<CMemLinker> *)m_pFree[i].GetNode(m_pFree[i].GetHead());
while (NULL != pLinker)
{
if (0 == pLinker->m_Value.m_dwCount)
{
//该结点不是原子结点
//(理论上不应出现此情况,此处表明程序出错了)
return 0xffffffff;
}
if (NULL == pLinker->m_Value.m_pMemAlloc)
{
//该结点没有从属的分配子
//(理论上不应出现此情况,此处表明程序出错了)
return 0xffffffff;
}
//记录其下一个待合并的结点
pNextLinker = pLinker->m_pNext;
while (pLinker->m_Value.m_dwCount < n)
{
pNextAtomicity = pLinker->m_Value.m_pMemAlloc->GetNextAtomicity(pLinker);
if (NULL == pNextAtomicity)
{
//下一个原子结点不存在
break;
}
else if (&m_Used == pNextAtomicity->m_pLinkList)
{
//下一个原子结点不是空闲结点
break;
}
else if (NULL == pNextAtomicity->m_pLinkList)
{
//(理论上不应出现此情况,此处表明程序出错了)
return 0xffffffff;
}
else
{
//若待合并结点就是pNextLinker
//更新pNextLinker
if (pNextAtomicity == pNextLinker)
{
pNextLinker = pNextLinker->m_pNext;
}
//合并pLinker与pNextAtomicity
pLinker->m_pLinkList->Remove(pLinker);
pLinker->m_Value.m_dwCount = pLinker->m_Value.m_dwCount + pNextAtomicity->m_Value.m_dwCount;
pNextAtomicity->m_pLinkList->Remove(pNextAtomicity);
pNextAtomicity->m_Value.m_dwCount = 0;
if (m_dwLevel < pLinker->m_Value.m_dwCount)
{
m_pFree[0].PushTail(pLinker);
}
else
{
m_pFree[pLinker->m_Value.m_dwCount].PushTail(pLinker);
}
}
}
if (pLinker->m_Value.m_dwCount > m_dwLevel)
{
//成功合并出足够逻辑分配需求的结点
return 0;
}
else if (pLinker->m_Value.m_dwCount >= n)
{
//成功合并出足够逻辑分配需求的结点
return pLinker->m_Value.m_dwCount;
}
else
{
//合并之后的结点依然不够分配
//尝试重新合并下一个结点
pLinker = pNextLinker;
}
}
}
return -1;
}
bool CMemoryPool::Free(const char *pBuff)
{
if (NULL == pBuff)
{
return false;
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
bool bRes = false;
char *pBuffAddr = (char *)pBuff;
TLeaf<char *, CMemoryAllocator> *pAllocLinker = m_MemAllocList.Find(pBuffAddr);
if (NULL != pAllocLinker)
{
TBDLinker<CMemLinker> *pLinker = pAllocLinker->m_Value.GetBuffLinker(pBuff);
if (NULL != pLinker)
{
if (NULL != pLinker->m_pLinkList)
{
DWORD n = pLinker->m_Value.m_dwCount;
DWORD nSize = n * m_dwUnitSize;
m_dwUseSize -= nSize;
pLinker->m_pLinkList->Remove(pLinker);
m_pFree[pLinker->m_Value.m_dwCount].PushTail(pLinker);
bRes = true;
}
}
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return bRes;
}
DWORD CMemoryPool::GetPoolSize()
{
return m_dwPoolSize;
}
DWORD CMemoryPool::GetUseSize()
{
return m_dwUseSize;
}
附加内存分配效率的测试结果,(与系统分配函数对比)
10W次内存分配操作,每次分配大小为1B-4096B随机大小,循环测试10次
测试代码
CPerformance perf;
float fTime = 0.0f;
srand(time(NULL));
//初始化参数
DWORD dwMaxMemSize = 1024 *1024 * 100;
DWORD dwAddMemSize = 1024 *1024 * 50;
DWORD dwUnitSize = 256;
DWORD dwMaxUnitSize = 4096;
//10W次的分配操作以及保存分配结果的数组
DWORD dwMaxAddrListLen = 100000;
char **pAddrList = new char *[dwMaxAddrListLen];
char *pBuff = NULL;//每次分配内存得到的地址
DWORD dwMemSize = 0;//每次分配内存大小的随机值
DWORD dwTotalMemSize = 0;//总共占用的内存大小
bool bRes = false;
CMemoryPool pool;
pool.Init(dwMaxMemSize,
dwAddMemSize,
dwUnitSize,
dwMaxUnitSize,
enum_JoinMemory,
enum_DisableLock_MemPool);
for (DWORD j = 0; j < 10; j++)//测10次
{
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//内存池的分配方式:
perf.Start();
for(DWORD i = 0; i < dwMaxAddrListLen; i++)
{
dwMemSize = rand() % dwMaxUnitSize + 1;
dwTotalMemSize += ((dwMemSize - 1) / dwUnitSize + 1) * dwUnitSize;
char *pBuff = pool.Malloc(dwMemSize);
if (NULL == pBuff)
{
printf("malloc faild\n");
getchar();
}
pAddrList[i] = pBuff;
}
fTime = perf.End();
printf("pool :size=%d time=%f ", dwTotalMemSize, fTime);
perf.Start();
for (DWORD i = 0; i < dwMaxAddrListLen; i++)
{
bRes = pool.Free(pAddrList[i]);
if (!bRes)
{
printf("Free faild\n");
getchar();
}
}
fTime = perf.End();
printf("free=%f\n", fTime);
dwTotalMemSize = 0;
fTime = 0.0f;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//new的分配方式:
perf.Start();
for(DWORD i = 0; i < dwMaxAddrListLen; i++)
{
dwMemSize = rand() % dwMaxUnitSize + 1;
dwTotalMemSize += dwMemSize;
char *pBuff = (char *)malloc(dwMemSize);
if (NULL == pBuff)
{
printf("malloc faild\n");
getchar();
}
pAddrList[i] = pBuff;
}
fTime = perf.End();
printf("malloc:size=%d time=%f ", dwTotalMemSize, fTime);
perf.Start();
for (DWORD i = 0; i < dwMaxAddrListLen; i++)
{
free(pAddrList[i]);
}
fTime = perf.End();
printf("free=%f\n\n", fTime);
dwTotalMemSize = 0;
fTime = 0.0f;
}
printf("over");
getchar();
测试结果贴图(单位毫秒)