文章目录
一. 申请内存流程梳理
二. 申请内存完整代码
1. Common.h
该头文件中包含公共的数据结构、方法、常量等。
#pragma once
#include <mutex>
#include <thread>
#include <iostream>
#include <assert.h>
#include <algorithm>
using std::cout;
using std::endl;
static const size_t NPAGES = 129; // PageCache可申请的最大页数
static const size_t PAGE_SHIFT = 13; // 通过移位运算计算页号和页的起始地址
static const size_t NFREELIST = 208; // 小块定长内存自由链表桶的数量
static const size_t MAX_BYTES = 256 * 1024; // ThreadCache可申请的最大内存空间
// 条件编译不同平台、系统的页号类型
#ifdef _WIN64
typedef unsigned long long PAGE_ID;
#elif _WIN32
typedef size_t PAGE_ID;
#else
//Linux
#endif
// 条件编译不同系统的系统头文件
#ifdef _WIN32
#include <windows.h>
#else
// Linux
#endif
// 条件编译不同系统到堆上以页为单位申请空间
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
// linux下brk mmap等
#endif
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}
// 返回传入空间的头4个或8个字节内容的引用
static inline void*& NextObj(void* obj)
{
assert(obj);
return *(void**)obj;
}
// 管理切分好的小块定长内存的自由链表
class FreeList
{
public:
// 头插一个小块定长内存
void PushFront(void* obj)
{
assert(obj);
NextObj(obj) = _freeList;
_freeList = obj;
++_size;
}
// 头删一个小块定长内存
void* PopFront()
{
assert(!Empty());
void* obj = _freeList;
_freeList = NextObj(obj);
--_size;
return obj;
}
// 头插批量小块定长内存
void PushRangeFront(void* start, void* end, size_t n)
{
assert(start);
assert(end);
assert(n > 0);
NextObj(end) = _freeList;
_freeList = start;
_size += n;
}
// 判断自由链表是否为空
bool Empty()
{
return _size == 0;
}
// 获取该链表像中心缓存申请内存时的慢启动调节值
size_t GetAdjustSize()
{
return adjustSize;
}
private:
size_t _size = 0; // 小块定长内存的数数量
size_t adjustSize = 1; // 向中心缓存申请内存的慢启动调节值
void* _freeList = nullptr; // 存储小块定长内存的自由链表
};
// 计算传入对象大小和小块定长内存的对齐映射规则
class SizeClass
{
// 整体控制在最多10%左右的内碎片浪费
// [1,128] 8byte对齐 freelists[0,16)
// [128+1,1024] 16byte对齐 freelists[16,72)
// [1024+1,8*1024] 128byte对齐 freelists[72,128)
// [8*1024+1,64*1024] 1024byte对齐 freelists[128,184)
// [64*1024+1,256*1024] 8*1024byte对齐 freelists[184,208)
public:
// 计算对齐后得到的定长块大小
static inline size_t RoundUp(size_t bytes)
{
if (bytes <= 128)
{
return _RoundUp(bytes, 8);
}
else if (bytes <= 1024)
{
return _RoundUp(bytes, 16);
}
else if (bytes <= 8 * 1024)
{
return _RoundUp(bytes, 128);
}
else if (bytes <= 64 * 1024)
{
return _RoundUp(bytes, 1024);
}
else if (bytes <= 256 * 1024)
{
return _RoundUp(bytes, 8 * 1024);
}
else
{
assert("ThreadCache over 256k\n");
return -1;
}
}
// 计算映射到哪一个自由链表桶