__malloc_alloc_template分配器:该分配器是对malloc、realloc以及free的封装:
当调用malloc和realloc申请不到内存空间的时候,会改调用oom_malloc()和oom_realloc(),这两个函数会反复调用用户传递过来的out of memory handler处理函数,直到能用malloc或者realloc申请到内存为止。
如果用户没有传递__malloc_alloc_oom_handler,__malloc_alloc_template会抛出__THROW_BAD_ALLOC异常。所以,内存不足的处理任务就交给类客户去完成。
__default_alloc_template分配器
这个分配器采用了内存池的思想,有效地避免了内碎片的问题(顺便一句话介绍一下内碎片和外碎片:内碎片是已被分配出去但是用不到的内存空间,外碎片是由于大小太小而无法分配出去的空闲块)。
如果申请的内存块大于128bytes,就将申请的操作移交__malloc_alloc_template分配器去处理;如果申请的区块大小小于128bytes时,就从本分配器维护的内存池中分配内存。
分配器用空闲链表的方式维护内存池中的空闲空间。
#include<iostream>
#include<stdarg.h>
using namespace std;
#define __DEBUG__
static string GetFileName(const string& path)
{
char ch = '/';
#ifdef _WIN32
ch = '\\';
#endif
size_t pos = path.rfind(ch);
if (pos == string::npos)
return path;
else
return path.substr(pos + 1);
}
// 用于调试追溯的trace log
inline static void __trace_debug(const char* function,
const char * filename, int line, char* format, ...)
{
#ifdef __DEBUG__
// 输出调用函数的信息
fprintf(stdout, "【%s:%d】 %s", GetFileName(filename).c_str(), line, function);
// 输出用户打的trace信息
va_list args;
va_start(args, format);
vfprintf(stdout, format, args);
va_end(args);
#endif
}
#define __TRACE_DEBUG(...) \
__trace_debug(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__);
typedef void(*MallocAllocHandler)();
template <int inst>
class MallocAllocTemplate
{
protected:
static MallocAllocHandler _handler;
static void* Oom_Malloc(size_t n)
{
MallocAllocHandler handler = NULL;
void* ret = NULL;
while (1)
{
handler = _handler;
if (handler == NULL)
{
cout << "out of memory" << endl;
//exit(1);
}
(*handler)();
ret = malloc(n);
if (ret)
return ret;
}
}
public:
static void * Allocate(size_t n)
{
void *result = malloc(n);
if (0 == result) result = Oom_Malloc(n);
__TRACE_DEBUG("调用一级空间配置器开辟内存:ptr:%p,size:%u\n", result,n);
return result;
}
static void Deallocate(void *p, size_t n)
{
free(p);
__TRACE_DEBUG("调用一级空间配置器释放内存:ptr:%p,size:%u\n", p, n);
}
static void(*SetMallocHandler(MallocAllocHandler f))()
{
void(*old)() = _handler;
_handler = f;
return(old);
}
};
template<int inst> MallocAllocHandler MallocAllocTemplate<inst>::_handler = NULL;
template <bool threads, int inst>
class DefaultAllocTemplate
{
enum { ALIGN = 8 };
enum { MAX_BYTES = 128 };
enum { NFREELISTS = MAX_BYTES / ALIGN };
union Obj {
union Obj * _freeListLink;
char _clientData[1]; /* The client sees this. */
};
static Obj * volatile _freeList[NFREELISTS];//指针数组
static char *_startFree;
static char *_endFree;
static size_t _heapSize;
static size_t FreeListIndex(size_t bytes) {
return (((bytes)+ALIGN - 1) / ALIGN - 1);
}
static size_t RoundUp(size_t bytes) {
return (((bytes)+ALIGN - 1) & ~(ALIGN - 1));
}
static char* chunkAlloc(size_t n, int& nobjs)
{
char* ret = NULL;
size_t totalBytes = n*nobjs;
size_t freeLeft = _endFree - _startFree;
if (freeLeft >= totalBytes)
{
ret = _startFree;
_startFree += totalBytes;
__TRACE_DEBUG("内存池足够分配空间:ptr:%p,size:%u\n", ret, totalBytes);
return(ret);
}
else if (freeLeft >= n)
{
nobjs = freeLeft / n;
totalBytes = n*nobjs;
ret = _startFree;
_startFree += totalBytes;
__TRACE_DEBUG("内存池只有空间:ptr:%p,size:%u\n", ret, totalBytes);
return(ret);
}
else
{
size_t bytesOfGet = 2 * totalBytes + RoundUp(_heapSize >> 4);
//将剩下的小块内存挂载
if (freeLeft > 0)
{
Obj* myFreeList = _freeList[FreeListIndex(freeLeft)];
((Obj*)_startFree)->_freeListLink = myFreeList;
_freeList[FreeListIndex(freeLeft)] = (Obj*)_startFree;
}
_startFree =(char*) malloc(bytesOfGet);
if (_startFree == NULL)
{
Obj* myFreeList, *p;
for (int i = n; i < MAX_BYTES; i += ALIGN)
{
myFreeList = _freeList[FreeListIndex(i)];
if (myFreeList != NULL)
{
p = myFreeList;
myFreeList = myFreeList->_freeListLink;
_startFree = (char*)p;
_endFree = _startFree + i;
return chunkAlloc(n, nobjs);//会进入else if
}
}
//空闲链表无比n大的内存
_endFree = NULL;//防止_startFree返回0,而_endFree为一个很大的值,误认为有内存池内存可分配
_startFree = (char*)MallocAllocTemplate<0>::Allocate(bytesOfGet);
}
_heapSize += bytesOfGet;
_endFree = _startFree + bytesOfGet;
return chunkAlloc(n, nobjs);//会进if
}
}
static void* Refill(size_t n)
{
int nobjs = 20;
char * chunk = chunkAlloc(n, nobjs);
Obj* volatile * myFreeList;
Obj* ret;
Obj * currentObj=NULL, *nextObj=NULL;
int i;
if (1 == nobjs) return(chunk);
myFreeList = _freeList + FreeListIndex(n);
ret = (Obj *)chunk;
*myFreeList = nextObj = (Obj *)(chunk + n);
/*for (i = 1;; i++) {
currentObj = nextObj;
nextObj = (Obj *)((char *)nextObj + n);
if (nobjs - 1 == i)
{
currentObj->freeListLink = 0;
break;
}
else
{
currentObj->freeListLink = nextObj;
}
}*/
//
for (i = 0; i < nobjs - 1; ++i)
{
currentObj = nextObj;
nextObj = nextObj + 1;
currentObj->_freeListLink = nextObj;
}
__TRACE_DEBUG("挂载空间到自由链表\n");
currentObj->_freeListLink = NULL;
return ret;
}
public:
static void Deallocate(void* p, size_t size)
{
if (size > MAX_BYTES)
{
MallocAllocTemplate<0>::Deallocate(p, size);
__TRACE_DEBUG("调用一级空间配置器释放内存:ptr:%p,size:%u\n",p,size);
}
else
{
Obj * myFreeList = _freeList[FreeListIndex(size)];
((Obj*)p)->_freeListLink = myFreeList;
_freeList[FreeListIndex(size)] = (Obj*)p;
__TRACE_DEBUG("挂载到自由链表释放内存:ptr:%p,size:%u\n", p, size);
}
}
static void * Allocate(size_t n)
{
Obj * volatile * myFreeList;
Obj * result;
if (n > MAX_BYTES)
{
return(MallocAllocTemplate<1>::Allocate(n));
}
myFreeList = _freeList + FreeListIndex(n);
result = *myFreeList;
if (result == NULL)
{
void* ret = Refill(RoundUp(n));
__TRACE_DEBUG("分配空间:ptr:%p\n", ret);
return ret;
}
*myFreeList = result->_freeListLink;
__TRACE_DEBUG("从自由链表直接取:ptr:%p,size:%u\n", result,n);
return result;
}
};
template<bool threads,int inst>
typename DefaultAllocTemplate<threads, inst>::Obj* volatile DefaultAllocTemplate<threads, inst>::_freeList[DefaultAllocTemplate<0, 0>::NFREELISTS] = { 0 };//指针数组
template<bool threads,int inst>
char* DefaultAllocTemplate<threads, inst>::_startFree = NULL;
template<bool threads, int inst>
char* DefaultAllocTemplate<threads, inst>::_endFree = NULL;
template<bool threads, int inst>
size_t DefaultAllocTemplate<threads, inst>::_heapSize = 0;
# ifdef __USE_MALLOC
typedef MallocAllocTemplate<0> Alloc;
typedef MallocAllocTemplate<0> Alloc;
# else
typedef DefaultAllocTemplate<0, 0> Alloc;
typedef DefaultAllocTemplate<0, 0> Alloc;
#endif
template<class T, class Alloc>
class SimpleAlloc
{
public:
static T *Allocate(size_t n) { return 0 == n ? 0 : (T*)Alloc::Allocate(n*sizeof(T)); }
static T *Allocate(void) { return (T*)Alloc::Allocate(sizeof(T)); }
static void Deallocate(T* p, size_t n) { if (0 != n) Alloc::Deallocate(p, n*sizeof(T)); }
static void Deallocate(T *p){ Alloc::Deallocate(p, sizeof(T)); }
//将调用传递给配置器的成员函数,可能是第一级也可能是第二级
};
void Test1()
{
//MallocAllocTemplate<1> d;
////int *p=(int*)MallocAllocTemplate<1>::Allocate(sizeof(int));
//int *p=(int*)d.Allocate(sizeof(int));
//*p = 2;
//cout << *p << endl;
//d.Deallocate(p, sizeof(int));
//DefaultAllocTemplate<0, 0> a;
//int* p1 = (int*)a.Allocate(sizeof(int));
//*p1 = 3;
//cout << *p1 << endl;
//typedef MallocAllocTemplate<0> Alloc;
// 测试调用一级配置器分配内存
cout << " 测试调用一级配置器分配内存 " << endl;
char*p1 = SimpleAlloc< char, Alloc>::Allocate(129);
SimpleAlloc<char, Alloc>::Deallocate(p1, 129);
// 测试调用二级配置器分配内存
cout << " 测试调用二级配置器分配内存 " << endl;
char*p2 = SimpleAlloc< char, Alloc>::Allocate(128);
char*p3 = SimpleAlloc< char, Alloc>::Allocate(128);
char*p4 = SimpleAlloc< char, Alloc>::Allocate(128);
char*p5 = SimpleAlloc< char, Alloc>::Allocate(128);
SimpleAlloc<char, Alloc>::Deallocate(p2, 128);
SimpleAlloc<char, Alloc>::Deallocate(p3, 128);
SimpleAlloc<char, Alloc>::Deallocate(p4, 128);
SimpleAlloc<char, Alloc>::Deallocate(p5, 128);
for (int i = 0; i < 21; ++i)
{
printf(" 测试第%d次分配 \n", i + 1);
char*p = SimpleAlloc< char, Alloc>::Allocate(128);
}
}
// 测试特殊场景
void Test2()
{
cout << " 测试内存池空间不足分配个 " << endl;
// 8*20->8*2->320
char*p1 = SimpleAlloc< char, Alloc>::Allocate(8);
char*p2 = SimpleAlloc< char, Alloc>::Allocate(8);
cout << " 测试内存池空间不足, 系统堆进行分配 " << endl;
char*p3 = SimpleAlloc< char, Alloc>::Allocate(12);
}
void Test3()
{
cout << " 测试系统堆内存耗尽 " << endl;
SimpleAlloc<char, Alloc>::Allocate(1024 * 1024 * 1024);
//SimpleAlloc<char, Alloc>::Allocate(1024*1024*1024);
SimpleAlloc<char, Alloc>::Allocate(1024 * 1024);
// 不好测试, 说明系统管理小块内存的能力还是很强的。
for (int i = 0; i < 100000; ++i)
{
char*p1 = SimpleAlloc< char, Alloc>::Allocate(128);
}
}
运行截图:
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。