Blame doc/tutorial_pools.dox

Packit Service fa3ceb
/**
Packit Service fa3ceb
@page libtalloc_pools Chapter 5: Memory pools
Packit Service fa3ceb
Packit Service fa3ceb
@section pools Memory pools
Packit Service fa3ceb
Packit Service fa3ceb
Allocation of a new memory is an expensive operation and large programs can
Packit Service fa3ceb
contain thousands of calls of malloc() for a single computation, where every
Packit Service fa3ceb
call allocates only a very small amount of the memory. This can result in an
Packit Service fa3ceb
undesirable slowdown of the application. We can avoid this slowdown by
Packit Service fa3ceb
decreasing the number of malloc() calls by using a memory pool.
Packit Service fa3ceb
Packit Service fa3ceb
A memory pool is a preallocated memory space with a fixed size. If we need to
Packit Service fa3ceb
allocate new data we will take the desired amount of the memory from the pool
Packit Service fa3ceb
instead of requesting a new memory from the system. This is done by creating a
Packit Service fa3ceb
pointer that points inside the preallocated memory. Such a pool must not be
Packit Service fa3ceb
reallocated as it would change its location - pointers that were pointing
Packit Service fa3ceb
inside the pool would become invalid. Therefore, a memory pool requires a very
Packit Service fa3ceb
good estimate of the required memory space.
Packit Service fa3ceb
Packit Service fa3ceb
The talloc library contains its own implementation of a memory pool. It is
Packit Service fa3ceb
highly transparent for the programmer. The only thing that needs to be done is
Packit Service fa3ceb
an initialization of a new pool context using talloc_pool() -
Packit Service fa3ceb
which can be used in the same way as any other context.
Packit Service fa3ceb
Packit Service fa3ceb
Refactoring of existing code (that uses talloc) to take the advantage of a
Packit Service fa3ceb
memory pool is quite simple due to the following properties of the pool context:
Packit Service fa3ceb
Packit Service fa3ceb
- if we are allocating data on a pool context, it takes the desired
Packit Service fa3ceb
  amount of memory from the pool,
Packit Service fa3ceb
- if the context is a descendant of the pool context, it takes the space
Packit Service fa3ceb
  from the pool as well,
Packit Service fa3ceb
- if the pool does not have sufficient portion of memory left, it will
Packit Service fa3ceb
  create a new non-pool context, leaving the pool intact
Packit Service fa3ceb
Packit Service fa3ceb
@code
Packit Service fa3ceb
/* allocate 1KiB in a pool */
Packit Service fa3ceb
TALLOC_CTX *pool_ctx = talloc_pool(NULL, 1024);
Packit Service fa3ceb
Packit Service fa3ceb
/* Take 512B from the pool, 512B is left there */
Packit Service fa3ceb
void *ptr = talloc_size(pool_ctx, 512);
Packit Service fa3ceb
Packit Service fa3ceb
/* 1024B > 512B, this will create new talloc chunk outside
Packit Service fa3ceb
   the pool */
Packit Service fa3ceb
void *ptr2 = talloc_size(ptr, 1024);
Packit Service fa3ceb
Packit Service fa3ceb
/* The pool still contains 512 free bytes
Packit Service fa3ceb
 * this will take 200B from them. */
Packit Service fa3ceb
void *ptr3 = talloc_size(ptr, 200);
Packit Service fa3ceb
Packit Service fa3ceb
/* This will destroy context 'ptr3' but the memory
Packit Service fa3ceb
 * is not freed, the available space in the pool
Packit Service fa3ceb
 * will increase to 512B. */
Packit Service fa3ceb
talloc_free(ptr3);
Packit Service fa3ceb
Packit Service fa3ceb
/* This will free memory taken by 'pool_ctx'
Packit Service fa3ceb
 * and 'ptr2' as well. */
Packit Service fa3ceb
talloc_free(pool_ctx);
Packit Service fa3ceb
@endcode
Packit Service fa3ceb
Packit Service fa3ceb
The above given is very convenient, but there is one big issue to be kept in
Packit Service fa3ceb
mind. If the parent of a talloc pool child is changed to a parent that is
Packit Service fa3ceb
outside of this pool, the whole pool memory will not be freed until the child is
Packit Service fa3ceb
freed. For this reason we must be very careful when stealing a descendant of a
Packit Service fa3ceb
pool context.
Packit Service fa3ceb
Packit Service fa3ceb
@code
Packit Service fa3ceb
TALLOC_CTX *mem_ctx = talloc_new(NULL);
Packit Service fa3ceb
TALLOC_CTX *pool_ctx = talloc_pool(NULL, 1024);
Packit Service fa3ceb
struct foo *foo = talloc(pool_ctx, struct foo);
Packit Service fa3ceb
Packit Service fa3ceb
/* mem_ctx is not in the pool */
Packit Service fa3ceb
talloc_steal(mem_ctx, foo);
Packit Service fa3ceb
Packit Service fa3ceb
/* pool_ctx is marked as freed but the memory is not
Packit Service fa3ceb
   deallocated, accessing the pool_ctx again will cause
Packit Service fa3ceb
   an error */
Packit Service fa3ceb
talloc_free(pool_ctx);
Packit Service fa3ceb
Packit Service fa3ceb
/* This deallocates the pool_ctx. */
Packit Service fa3ceb
talloc_free(mem_ctx);
Packit Service fa3ceb
@endcode
Packit Service fa3ceb
Packit Service fa3ceb
It may often be better to copy the memory we want instead of stealing it to
Packit Service fa3ceb
avoid this problem. If we do not need to retain the context name (to keep the
Packit Service fa3ceb
type information), we can use talloc_memdup() to do this.
Packit Service fa3ceb
Packit Service fa3ceb
Copying the memory out of the pool may, however, discard all the performance
Packit Service fa3ceb
boost given by the pool, depending on the size of the copied memory. Therefore,
Packit Service fa3ceb
the code should be well profiled before taking this path. In general, the
Packit Service fa3ceb
golden rule is: if we need to steal from the pool context, we should not
Packit Service fa3ceb
use a pool context.
Packit Service fa3ceb
Packit Service fa3ceb
*/