FrameAllocator通过帧级批量分配与重置规避内存碎片:预分配大页、线性分配无释放、整帧统一归还,适用于存活期严格对齐帧边界的短期对象。

FrameAllocator 为什么能缓解游戏内存碎片
游戏每帧动态分配大量短期对象(比如粒子、临时计算结果、UI 布局缓存),用 new 或 malloc 频繁申请/释放小块内存,极易导致堆内存碎片——不是没内存,而是找不到连续小块。而 FrameAllocator 本质是“一帧一清”的线性缓冲区:只推进指针、不回收中间内存,彻底规避了 free 引起的空洞和合并开销。
- 它不管理单个对象生命周期,只保证整块内存在帧结束时统一归还
- 所有分配都在一个预分配的大页(如 2MB)内线性进行,无元数据开销、无锁、无查找
- 适合对象存活期严格对齐帧边界(从 Alloc 到本帧结束前都有效)的场景
怎么写一个最小可用的 FrameAllocator
核心是维护一个当前偏移 m_offset 和总大小 m_capacity,分配即原子加法,重置即置零:
class FrameAllocator {
char* m_buffer;
size_t m_capacity;
std::atomic<size_t> m_offset{0};
public:
FrameAllocator(size_t cap) : m_capacity(cap) {
m_buffer = static_cast<char>(std::aligned_alloc(64, cap));
}
~FrameAllocator() { std::free(m_buffer); }
<pre class="brush:php;toolbar:false;">void* allocate(size_t size, size_t align = 64) {
size_t offset = m_offset.fetch_add(size + align, std::memory_order_relaxed);
size_t aligned = (offset + align - 1) & ~(align - 1);
if (aligned + size > m_capacity) return nullptr;
return m_buffer + aligned;
}
void reset() { m_offset.store(0, std::memory_order_relaxed); }
};
-
std::aligned_alloc确保缓冲区本身对齐,allocate()内部再做地址对齐 - 不检查溢出时的 fallback 行为(如抛异常或切到堆),这由上层逻辑决定
-
reset()必须在帧末显式调用,不能依赖析构——否则下一帧就失效
哪些地方该用 FrameAllocator,哪些不该用
用对地方才能见效,乱用反而引入 bug:
✅ 适合:粒子系统每帧生成的
Particle实例、动画采样临时数组、ECS 的临时查询结果、UI 布局计算中的Rect栈❌ 不适合:需要跨帧存活的对象(如玩家角色组件、资源句柄)、需单独释放的子内存(比如分配一块 buffer 后再其中
free某段)、STL 容器(std::vector默认用全局new,需传自定义Allocator)若对象析构有副作用(如日志、计数、资源解绑),
FrameAllocator不会调用析构函数——必须手动在reset()前遍历并显式调用,或改用带析构支持的变体(如 arena + 对象列表)-
多线程下若多个 worker 共享同一
FrameAllocator,allocate()必须用原子操作,但reset()仍需同步点(如主线程 wait 所有 worker 完成)
和标准堆混用时最常踩的坑
最大的陷阱不是性能,而是语义混淆:
把
FrameAllocator::allocate()返回的指针传给delete或free()→ 直接 crash,因为地址不在堆管理范围内在帧中用
FrameAllocator分配对象,却在另一帧的 lambda 里捕获并试图访问 → 悬垂指针,reset()后内存已被视为可覆盖把
FrameAllocator当作通用池复用,长期持有某次分配的指针 → 一帧后整个 buffer 被重置,所有指针全部失效调试时可在
allocate()中记录调用栈(用__builtin_return_address或backtrace),配合帧号打日志,快速定位越界使用发布版建议关闭调试记录,但保留
assert(aligned + size 防止静默溢出写坏相邻内存
帧分配器不是银弹,它把内存管理责任从运行时搬到了程序员手上——你得清楚每个字节的生与死发生在哪一帧。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











