Show Contents Previous Page Next Page
Chapter 10 - C API Reference Guide, Part I Memory Management and Resource Pools In this section... Introduction Show Contents Go to Top Previous Page Next Page If you've ever developed a moderately complex C-language
program, you've struggled with memory management. It's
not easy to manage memory in C: failing to deallocate
a data structure when you're through with it gives rise
to memory leaks, and conversely, disposing of the same
data structure twice is likely to lead to a crash. It's
one thing to have a small memory leak in your own program.
Unless the leak is very severe, the program will probably
finish execution and exit normally before memory becomes
tight. However, it's quite another issue to have memory
management problems in a network server, which is expected
to run for weeks or months at a time. Even small leaks
can add up over time, and a dangling pointer or a doubly
deallocated block can make the whole server crash. The Apache server developers were aware of the challenge
of memory management, and so they devised a system to
make life easier both for themselves and for module
writers. Instead of managing memory directly, Apache
module developers take the memory they need from one
or more resource pools. An Apache pool
structure keeps track of all module memory allocations
and releases all allocated blocks automatically when
the lifetime of the pool has ended. Different pools have different lifetimes: one lasts
for the lifetime of a child, one for the lifetime of
a request, another for the module configuration phase,
and so forth. However, the nicest feature about pools
is that the programmer generally doesn't need to know
a pool's lifetime. Apache passes the appropriate pool
pointer to your callback functions during the various
start-up, configuration, and request phases. Depending
on the context, sometimes the pool is passed directly
to your subroutine as an argument, and sometimes it
is tucked away inside one of the other data structures
needed by the subroutine, such as the request_rec
or conn_rec structures. Most memory management is performed within the various
request phase handlers. In this case, the resource pool
to draw from will be found inside the request_rec .
Any resources associated with this pool will not be
released until the very end of a request (after logging).
This arrangement may not be suited to certain very specialized
modules. For example, the mod_autoindex module
needs to make many short-lived memory allocations while
it is generating directory listings. In this case, modules
can create subpools, which are private resource pools
allocated from within the main resource pool. The module
can allocate blocks from within its subpool and destroy
the subpool when it's no longer needed. If a module
screws up and forgets to deallocate its subpool, no
permanent harm is done. The subpool is deleted when
its parent resource pool is cleaned up at the end of
the request. Once a memory block is allocated from a pool, there
is no easy way to deallocate it. Normally you will wait
for the pool to expire naturally. However, if you have
created a subpool to work with, you can delete the whole
subpool (and all its contained memory blocks) in one
fell swoop. Memory and String Allocation Routines Show Contents Go to Top Previous Page Next Page All memory-handling API routines are defined in the
include file include/alloc.h, which is brought
in automatically when you include include/httpd.h.
The routines for allocating and freeing blocks of pool
memory are all named after the familiar C library functions
with the prefix ap_p tacked onto the front.
void *ap_palloc (struct pool *p, int nbytes)
This function works just like using malloc(),
but you don't have to worry about calling free()
(in fact, you should not). The memory will be cleaned
up for you when the pool reaches the end of its lifetime.
You must pass the ap_palloc() function a
pointer to a preallocated pool, such as the one recovered
from the request record. In this example, we create
a C string large enough to accommodate len
characters (plus terminating byte):
char *string = (char*)ap_palloc(r->pool, len + 1);
If there is insufficient memory to satisfy your request,
ap_palloc() will return null. You should check
for this condition and take appropriate action.
void *ap_pcalloc (struct pool *p, int nbytes)
This works just like the standard calloc()
function; it calls memset() to initialize
the memory to a block of '\0' bytes.
In this example, we create a hello_dir_config
structure (defined elsewhere) that is initially cleared
out:
hello_dir_config *cfg =
(hello_dir_config*)ap_pcalloc(p, sizeof(hello_dir_config));
char *ap_pstrdup (struct pool *p, const char *s)
This function works like the standard strdup()
function to duplicate a string, but the new string
is allocated from the indicated pool:
char *copy = ap_pstrdup(r->pool, string);
char *ap_pstrndup (struct pool *p, const char *s, int n)
This is a version of ap_pstrdup(), but
it only allocates and copies n bytes.
char *copy = ap_pstrndup(r->pool, string, len);
char *ap_pstrcat (struct pool *p,...)
This function is similar to the standard strcat()
function, but it accepts a variable list of string
arguments to join together, returning the result as
a newly allocated character string. The list of strings
must be NULL -terminated:
char *string = ap_pstrcat(r->pool, "<", html_tag, ">", NULL);
char *ap_psprintf (struct pool *p, const char *fmt, ...)
This function works like the standard sprintf(),
but it is much safer than the standard version because
it allocates the requested memory from the pool, rather
than writing the string into a static buffer. (Standard
sprintf() has recently triggered a number
of CERT advisories for some popular pieces of Internet
software.) Here is an example of the function's usage:
char *string = ap_psprintf(r->pool, "<%s>", html_tag);
char *ap_cpystrn (char *dest, const char *source, size_t maxlen)
While this function is not tied to a pool, we list
it here with the other string manipulation functions.
In this version of the standard strncpy()
function, the destination string is always guaranteed
to be NULL -terminated, even if the entire
source string was not copied. Furthermore, the return
value points to the terminating '\0'
byte rather than to the beginning of the string, allowing
you to check more easily for truncation. Another difference
from the standard function call is that ap_cpystrn()
does not null-fill the string, although this will
be rarely noticed in practice.
result = ap_cpystrn(to, from, len);
if ((result - to) == len) {
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
server_rec, "truncation during ap_cpystrn()");
}
int ap_snprintf (char *dest, size_t len, const char *fmt, ...)
We again list this string manipulation function
here, although it is not directly tied to a pool.
This is a version of the snprintf() function,
which comes with some versions of the standard C library.
Because snprintf() isn't available on all
platforms, the Apache version provides portability.
char string[MAX_STR_LEN];
ap_snprintf(string, sizeof(string), "<%s>", html_tag);
Subpool Management Show Contents Go to Top Previous Page Next Page You will probably never need to manage your own subpools,
since there should always be a pool available during
the various phases that will be cleaned up when the
time is right. However, if your module is allocating
a considerable amount of memory, you may need tighter
management over when pools are released. This you can
do by allocating and destroying private subpools. struct pool *ap_make_sub_pool (struct pool *p)
Given an existing pool, this call returns a subpool.
You can then allocate blocks of memory from within
the subpool using the routines described above. When
the parent pool is released, your subpool will be
destroyed along with it, or you can destroy the pool
yourself using the routine described next. A new pool
can also be created without a parent pool by passing
in a NULL argument. In this case, such
code will be completely responsible for destroying
the new pool.
void ap_destroy_pool (pool *p)
This function destroys the pool or subpool along
with all its contents. Once a pool has been destroyed,
be careful not to use any pointers to memory blocks
that were allocated from within it!
void ap_clear_pool (struct pool *p)
ap_clear_pool() destroys the contents
of the pool but leaves the pool itself intact. The
pool is returned to its initial, empty state and can
be used to allocate new blocks. Show Contents Go to Top Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |