前言
在 C++ 后端开发、游戏引擎、高频交易等场景中,频繁的 new/delete 操作会带来巨大的性能开销 —— 系统调用的上下文切换、内存碎片的产生、堆内存的锁竞争,都是性能瓶颈的元凶。
为了解决这个问题,内存池(Memory Pool) 应运而生。它的核心思想是:一次性向操作系统申请一大块连续内存,后续对象的创建和销毁都在这块内存上完成,避免频繁的系统调用,同时复用内存减少碎片。
本文将带你从零实现一个定长内存池(针对固定大小对象优化),深入讲解核心原理,并通过性能测试对比,验证其相比原生 new/delete 的性能优势。
一、定长内存池核心原理
定长内存池专为固定大小的对象设计(比如树节点、消息结构体、自定义类实例等),核心逻辑可以概括为 3 步:
- 批量预分配:向操作系统一次性申请一大块内存(如 128KB),作为'内存池'。
- 按需切分复用:创建对象时,从预分配的内存中切出一小块;销毁对象时,不释放给操作系统,而是将内存块加入'空闲链表'复用。
- 无锁高效:单线程场景下,全程无锁操作,分配和释放仅需指针操作,时间复杂度 O(1)。
关键技术点
- 空闲链表(Free List):用链表记录可复用的内存块,分配时取表头,释放时头插,效率极高。
- 定位 new(Placement New):在已分配的内存上调用构造函数,完成对象初始化。
- 显式析构:释放对象时手动调用析构函数,清理资源,再将内存加入空闲链表。
- 系统级内存申请:使用
VirtualAlloc(Windows)/mmap(Linux)直接向操作系统申请页对齐内存,减少内存碎片。
二、定长内存池完整实现
我们将代码分为两部分:内存池核心实现(ObjectPool.h) 和 性能测试代码(Test.cpp),结构清晰,便于复用和测试。
1. 内存池核心代码(ObjectPool.h)
#pragma once
#include <cstddef>
#include <new>
#include <stdexcept>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
{
* ptr = (, kpage * , MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
* ptr = (, kpage * , PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, , );
(ptr == MAP_FAILED) ptr = ;
(!ptr) std::();
ptr;
}
< >
{
:
{
T* obj = ;
(_freeList) {
* next = *<**>(_freeList);
obj = <T*>(_freeList);
_freeList = next;
} {
(_remainBytes < (T)) {
_remainBytes = * ;
_memory = <*>((_remainBytes / ));
(!_memory) std::();
}
obj = <T*>(<*>(_memory));
objSize = ((T) < (*)) ? (*) : (T);
_memory += objSize;
_remainBytes -= objSize;
}
(obj) T{};
obj;
}
{
(!obj) ;
obj->~();
*<**>(<*>(obj)) = _freeList;
_freeList = obj;
}
:
* _memory = ;
_remainBytes = ;
* _freeList = ;
};

