I know that the CrtAllocator
is the C runtime allocator and uses malloc
/realloc
/free
, and I know that the MemoryPoolAllocator
is the default allocator and allocates memory sequentially
.
I don't understand why the MemoryPoolAllocator
is considered more efficient than the CrtAllocator
. Does the MemoryPoolAllocator
just default allocate a large block of memory and just add entries into it each time Parse()
is called? If so, does that mean the CrtAllocator
calls malloc
for every new Parse()
?
The docs indicate this for the 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.
but it does not explain why it is better for a lot of adds/remove vs the MemoryPoolAllocator
or why/how it is far less efficient than MemoryPoolAllocator
.
The primary use case I care about is quickly parsing JSON responses from the Web. My plan is to just allocate a large buffer and reuse it for every response. I think I can just use ParseInsitu()
and clear the buffer every time.
Does it matter which Allocator I use for this use-case?
If you're simply grabbing a huge block of memory once and implementing your own memory pooling, just use the crtAllocator
. Otherwise use the MemoryPoolAllocator
which effectively borrows memory from the system and subdivides it as and when required.
Using a memory pool means that when a memory grab request is made, you keep the code running in user space, so there is no context-switching to kernel/protected mode and there is no need to possibly wait for mutexes for the kernel's memory allocator. (Unless it needs to borrow more memory to satisfy a memory grab request, but this won't be often).
The caveat is that the program would appear to be "using" more memory than it would otherwise need to; you're effectively bolting on a massive cache. Also you may need to pay attention to how the blocks are managed by the pooler if fragmentation becomes an issue. Managers such as Delphi's FastMM
provides different areas for small, medium and large blocks to mitigate this.
In most cases any downsides of a Memory Pool shouldn't be a problem though; use everything in moderation ;)
Check out the Wikipedia article: https://en.wikipedia.org/wiki/Memory_pool
In your case you may wish to just use CrtAllocator to make an initial memory grab, and then free it and grab a bigger block if it needs to grow. You might then consider freeing that at a later stage if the system memory becomes constrained. You may even want to consider keeping a small block
and a large block
so that the small block is always resident but you could let the large block come and go.
This keeps the memory footprint low, but allows you to also handle large requests, but also deny large requests if memory becomes constrained, whilst keeping the small block such that you don't end up with a situation of having no memory to grab at all.