什么时候应该在 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
以便小块始终驻留,但您可以让大块来来去去。
这可以保持低内存占用,但也允许您处理大型请求,但如果内存变得受限,也可以拒绝大型请求,同时保持小块,这样您就不会遇到没有完全可以抓住内存。
我知道 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
以便小块始终驻留,但您可以让大块来来去去。
这可以保持低内存占用,但也允许您处理大型请求,但如果内存变得受限,也可以拒绝大型请求,同时保持小块,这样您就不会遇到没有完全可以抓住内存。