Files
XCEngine/docs/api/_guides/Memory/Allocator-Selection-And-Current-Limits.md

4.0 KiB

Allocator Selection And Current Limits

为什么引擎要有多种分配器

商业级引擎不会把所有内存都交给一套通用堆分配器。原因很现实:

  • 帧级临时数据的生命周期极短,逐块释放反而是额外成本。
  • 大量固定尺寸对象如果走通用堆,碎片和元数据开销通常不划算。
  • 调试阶段又往往需要单独统计某个系统到底分了多少内存。

这就是 XCEngine::Memory 当前这组 API 的设计出发点。

现在这几个分配器分别适合什么

LinearAllocator

适合:

  • 一整批数据统一释放
  • 帧级或阶段级临时内存
  • 极低开销的顺序分配

不适合:

  • 需要单个对象独立释放
  • 需要通用 realloc

如果你熟悉 Unity 或其它引擎,可以把它理解为更接近 arena / frame allocator 这一类思路,而不是常驻对象堆。

PoolAllocator

适合:

  • 固定尺寸或尺寸上界稳定的对象
  • 高频分配 / 释放
  • 想避免通用堆碎片

不适合:

  • 大小变化大的对象
  • 需要可变尺寸重分配

ProxyAllocator

适合:

  • 给现有分配器加统计视图
  • 调试某个系统的内存用量
  • 不想修改底层分配器实现,但想额外记录指标

不适合:

  • 被当作完整可信的内存分析器

当前版本最需要诚实面对的事

这套模块已经有了不错的 API 形状,但实现还没有完全跟上。

最重要的限制有这些:

  • LinearAllocator::FreeReallocate 还没有完成。
  • PoolAllocator::Reallocate 还没有完成。
  • ProxyAllocator 的释放统计当前不准确。
  • MemoryManager 的泄漏和报表接口现在只是占位输出。
  • 部分统计方法名字很强,但当前返回值更接近“固定上界”而不是真实历史峰值。
  • 通过 MemoryManager 创建且依赖系统分配器的对象,目前仍要求调用方在 Shutdown() 之前主动销毁。

这意味着当前更合理的使用方式是:

  • 把这些分配器当作明确生命周期的工具型组件;
  • 不要把它们当成已经完备的内存诊断平台。

如何选择

如果你只是要一块批量临时内存:

auto allocator = XCEngine::Memory::MemoryManager::Get().CreateLinearAllocator(1024 * 1024);

如果你要大量固定尺寸对象:

auto allocator = XCEngine::Memory::MemoryManager::Get().CreatePoolAllocator(sizeof(MyNode), 1024);

如果你要统计某个系统的分配情况:

auto allocator = XCEngine::Memory::MemoryManager::Get().CreateProxyAllocator("RenderGraph");

这里还要额外记住一点:

  • CreateProxyAllocator() 应在 Initialize() 之后调用。
  • CreateLinearAllocator() 如果绑定了系统分配器作为父分配器,也应在 Shutdown() 前完成销毁。

为什么要保留 IAllocator

IAllocator 的价值不在“虚函数本身”,而在于它允许上层容器和子系统表达“我需要一个分配策略”,而不是“我必须依赖某个具体实现”。

这和很多商业引擎里的思路一致:

  • 容器依赖 allocator 接口
  • 上层根据数据生命周期决定用哪种分配器
  • 调试阶段可以额外套 tracking / proxy 层

当前阶段最值得补的方向

如果继续把这个模块做实,最值得优先补的通常是:

  1. LinearAllocatorPoolAllocator 明确补完 Reallocate / 回收语义,或者在 API 层彻底禁掉不支持的操作。
  2. 修正 ProxyAllocator 的统计口径。
  3. MemoryManager 的泄漏与报表接口真正产出结构化结果。
  4. 为不同分配器补充更严格的越界、重复释放和对齐校验。

相关 API