定长内存池通常被用作对象池(ObjectPool),整个内存池只用来给一种数据结构用。
对象池适用于以下场景:
- 高成本初始化:如 StringBuilder 或大型缓冲区。
- 有限资源:如数据库连接或线程。
- 频繁使用:如在高并发环境中重复使用的对象
1. 定长内存池的介绍
作为程序员(C/C++)我们知道申请内存使用的是 malloc,malloc 其实就是一个通用的大众货,什么场景下都可以用,但是什么场景下都可以用就意味着什么场景下都不会有很高的性能。下面我们就先来设计一个定长内存池做个开胃菜,当然这个定长内存池在我们后面的高并发内存池中也是有价值的,所以学习它目的有两层,先熟悉一下简单内存池是如何控制的,第二它会作为我们后面内存池的一个基础组件。
2. 定长内存池的构建
2.1 内存申请的系统调用
由于 malloc 的局限性,我们在内存申请方面使用系统调用,提高效率。
并且在操作系统中,系统通常以页为单位进行数据的访问和保存,通常一页是 4kb/8kb(我们选择 8kb),所以我们向系统申请内存时,最好是以页为单位申请。
关于内存申请的系统调用:
Windows: VirtualAlloc Linux: brk() 和 mmap()
我们再把系统调用封装一层(函数内),利用条件编译,可以实现跨平台使用。
#define PAGE_SHIFT 13 // (kpage << PAGE_SHIFT) 表示一页的字节大小 8kb = 8 * 1024,即 2*13
#ifdef _WIN32
#include <Windows.h>
#elif __linux__
#include <unistd.h>
#endif
// 直接去堆上按页申请空间
// 封装系统调用
inline static void* SystemAlloc(size_t kpage) // kpage:页数
{
#ifdef _WIN32
void* ptr = VirtualAlloc(0, kpage << PAGE_SHIFT, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
void* ptr = mmap(NULL, kpage << PAGE_SHIFT, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, , );
(ptr == MAP_FAILED) ptr = ;
(ptr == ) std::();
ptr;
}


