什么时候应该在 RapidJSON 中使用 CrtAllocator 与 MemoryPoolAllocator?

When should you use CrtAllocator vs MemoryPoolAllocator in RapidJSON?

我知道 CrtAllocator 是 C 运行时分配器并使用 malloc/realloc/free,我知道 MemoryPoolAllocator 是默认分配器和 allocates memory sequentially.

我不明白为什么 MemoryPoolAllocator 被认为比 CrtAllocator 更有效。 MemoryPoolAllocator 是否只是默认分配一大块内存并在每次调用 Parse() 时只向其中添加条目?如果是这样,这是否意味着 CrtAllocator 为每个新的 Parse() 调用 malloc

文档为 CrtAllocator 指出了这一点:When there is a lot of add and remove operations, this allocator may be preferred. But this allocator is far less efficient than MemoryPoolAllocator. 但它没有解释为什么它对很多 adds/remove 比 MemoryPoolAllocator 或 why/how 是 far less efficient than MemoryPoolAllocator.

我关心的主要用例是快速解析来自 Web 的 JSON 响应。我的计划是只分配一个大缓冲区并为每个响应重用它。我想我可以每次都使用 ParseInsitu() 并清除缓冲区。

我在这个用例中使用哪个分配器重要吗?

如果您只是简单地获取一次巨大的内存块并实现您自己的内存池,只需使用 crtAllocator。否则使用 MemoryPoolAllocator 有效地从系统借用内存并在需要时细分它。

使用内存池的意思是当有内存抢夺请求时,你将代码运行保留在用户space中,所以没有context-switching到kernel/protected 模式,并且不需要等待内核内存分配器的互斥量。 (除非它需要借用更多的内存来满足内存抢夺请求,但这种情况不会经常发生)。

需要注意的是,程序似乎“使用”了比原本需要的更多的内存;您实际上是在使用大量缓存。如果碎片成为问题,您还可能需要注意池如何管理块。 Delphi 的 FastMM 等管理器为小型、中型和大型区块提供了不同的区域来缓解这种情况。

在大多数情况下,内存池的任何缺点都应该不是问题;适度使用一切 ;)

查看维基百科文章:https://en.wikipedia.org/wiki/Memory_pool


在您的情况下,您可能希望只使用 CrtAllocator 进行初始内存获取,然后释放它并在需要增长时获取更大的块。如果系统内存变得受限,您可能会考虑在稍后阶段释放它。您甚至可能想考虑保留一个 small block 和一个 large block 以便小块始终驻留,但您可以让大块来来去去。

这可以保持低内存占用,但也允许您处理大型请求,但如果内存变得受限,也可以拒绝大型请求,同时保持小块,这样您就不会遇到没有完全可以抓住内存。