Search code examples
c++boost-pool

How does boost.pool achieve re-use of allocated memory?


Background

My previous question about boost.pool led me to investigate boost.pool in detail, and now I have a supplementary question to finalize my understanding.

Prelude

This reference states the following about the object pool pattern:

The object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use, rather than allocating and destroying them on demand.

From what I can tell, boost.pool (simplified) implements the object pool pattern by means of memory allocation and management mostly based on the size of an element_type, and returns a simple pointer to an allocated object:

element_type * malloc();
void free(element_type * p);

A simple boost example also shows that it is not necessary to explicitly free the acquired element:

X * const t = p.malloc();
... // Do something with t; don't take the time to free() it.

Question

I understand that the allocated memory will be safely freed on destruction of the pool object, but how does the pool know when a block of memory acquired by a client has been released back into the pool and is reusable if its interface hands back a direct pointer to element_type, yet a call to free() is still not required? i.e. How can the boost pool re-use this memory if it cannot be certain that the memory is not still in use? And if it does not re-use this memory, is this even considered the same pattern as the one explained by the wiki reference?


Solution

  • How can the boost pool re-use this memory if it cannot be certain that the memory is not still in use?

    It can't. In fact it won't reuse that memory. It only guarantee that you will have no leaks when the pool is destroyed.

    And if it does not re-use this memory, is this even considered the same pattern as the one explained by the wiki reference?

    The article you linked says: Object pooling can offer a significant performance boost in situations where the cost of initializing a class instance is high

    While from Boost pool introduction: Pools are generally used when there is a lot of allocation and deallocation of small objects.

    So no, they are not the same pattern. One is meant to re-use objects which are expensive to construct (threads, opengl resources, etc.). The other is meant to manage a lot of small objects, giving you more control than the standard allocator gives.

    As you pointed out, there are two ways of using pools:

    1. As an allocator, calling malloc()/free() when appropriate. This is the basic pool-allocator usage, it helps to reduce memory fragmentation
    2. Construct a ton of temporary objects and don't bother to delete them.

    Example for the second case: imagine you have a graph class, where each node stores its neighbors using pointers. Now you have to make a deep copy of your graph. You will allocate a bunch of new nodes and copy the data from the old ones to the new ones, but now you have to initialize neighbors pointers, so you need a map from old pointers to new pointers:

    std::map<node*,node*> old_ptr_to_new_ptr;
    

    This is a good example where pool allocators are useful (I won't go into detail about how to use pool allocators with std containers): a lot of small objects (map nodes) which are going to be deleted all together.