|
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 |
*/
|