apache 中的apr_pool(内存池概览)

apr_pool是libapr库中用于内存管理的关键组件,它简化了内存块的分配和释放,防止内存泄漏。通过创建内存池,可以一次性分配多个内存块,并在结束时只需销毁内存池来释放所有内存。apr_pool提供了apr_pool_create、apr_palloc和apr_pool_destroy等基本API。使用内存池可以降低内存分配的成本,并强制实现会话导向的编程。此外,还可以通过apr_pool_cleanup_register注册清理函数,当内存池被清除或销毁时自动执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

APR_POOL 帮助文档

Directory tree

1.       Brief introduction of apr_pool--------------------------------

2.       There are three basic APIs as follows:----------------------

APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool,

                                          apr_pool_t *parent);

APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size);

                         APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);

                           i.               

3.      Give a demonstration----------------------------------------------

4.       The detail-----------------------------------------------------------

5.       The contrast apr_palloc/apr_pcallo between malloc/ cal lo---------------------------------------------------------------

( Apr_pool_clearn and apr_pool_destroy------------------------- )

6.      Delegate or hook function-------------------------------------

7.   Apr_pool_cleanup_register and apr_pool_cleanup_kill-

8.       Sub pool-------------------------------------------------------------

 

Brief introduction of apr_pool

Most of libapr APIs are dependent on memory pool. By memory pool, you can easily manage a set of memory chunks. Imagine the case without memory pool system, where you allocate several memory chunks. You have to free each of them. If you have ten memory chunks, you have to free ten times, otherwise you would suffer from memory leak bugs. Memory pool solves this issue. After you allocate one memory pool, you can allocate multiple memory chunks from the pool. To free them, all you have to do is to destroy the memory pool. By which, you can free all the memory chunks. There are two good points. First, as stated above, it is defensive against memory leak bugs. Second, allocation costs of memory chunks become relatively lower. In a sense, memory pool forces you to obey a session-oriented programming. A memory pool is a kind of a session context, that is, a set of objects that have the same lifetimes. You can control a set of objects within a session context. At the beginning of a session you create a memory pool. Then, you create objects in the memory pool during the session. Note that you don't need to care about their lifetimes. Finally, at the end of the session all you have to do is to destroy the memory pool.

 

REMARK: In general, objects lifetime control is the most difficult part in programming. Thus, there are many other techniques for it, such as smart pointer, GC(garbage collection) and so on. Note that it is a bit hard to use such techniques at the same time. Since memory pool is one of such techniques, you have to be careful about the mixture.

There are three basic APIs as follows:

/* excerpted from apr_pools.h */

APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool,

                                          apr_pool_t *parent);

APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size);

APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);

 

Give a demonstration

 

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>

 

#include <apr_general.h>

#include <apr_pools.h>

 

#define MEM_ALLOC_SIZE            1024

 

/**

  * memory pool sample code

  * @remark Error checks omitted

  */

int main(int argc, const char *argv[])

{

    apr_status_t rv;

    apr_pool_t *mp;

    char *buf1;

    char *buf2;

 

    /* per-process initialization */

    rv = apr_initialize();

    if (rv != APR_SUCCESS) {

         assert(0);

        return -1;

    }

 

    /* create a memory pool. */

    apr_pool_create(&mp, NULL);

 

    /* allocate memory chunks from the memory pool */

    buf1 = apr_palloc(mp, MEM_ALLOC_SIZE);

    buf2 = apr_palloc(mp, MEM_ALLOC_SIZE);

 

    /* destroy the memory pool. These chunks above are freed by this */

    apr_pool_destroy(mp);

 

    apr_terminate();

    return 0;

}

The detail

/**

  * Create a new pool.

  * @param newpool The pool we have just created.

  * @param parent The parent pool.  If this is NULL, the new pool is a root

  *        pool.  If it is non-NULL, the new pool will inherit all

  *        of its parent pool's attributes, except the apr_pool_t will

  *        be a sub-pool.

  */

APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool,

                                          apr_pool_t *parent);

 

 

/*

  * Memory allocation

  */

 

/**

  * Allocate a block of memory from a pool

  * @param p The pool to allocate from

  * @param size The amount of memory to allocate

  * @return The allocated memory

  */

APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size);

 

 

/**

  * Destroy the pool. This takes similar action as apr_pool_clear() and then

  * frees all the memory.

  * @param p The pool to destroy

  * @remark This will actually free the memory

  */

APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);

 

Remark

We create a memory pool by apr_pool_create(). The memory pool is alive until you call apr_pool_destroy(). The first argument of apr_pool_create() is a result argument. A newly created memory pool object, apr_pool_t, is returned by this API call. We call apr_palloc() to get a memory chunk by specifing the chunk's size. someone think it should have a function to free the memory chunk.

But,in fact, the APIs do not provide such function.That is needless. The memory chunkes that you allo-

cated through apr_palloc() will be destroyed by apr_pool_destroy(). Overview,the only way to destroy

memory chunkes is destroy the memory pool by calling the apr_pool_destroy.

   We should take notice of the rv = apr_initialize() and apr_terminate(). The apr_initialize() is setup any APR internal data structures. This must be the first function called for any APR library.See apr_app_initalize() if this is an application , rather than a library consumer of apr.You must be close apr with a call to apr_terminate at the end of program execution.

The contrast apr_palloc/apr_pcalloc between malloc/calloc

    As you can guess, we can use apr_palloc() like malloc().The different between them is that the apr_palloc() is allocate and manage memory chunk by the memory pool,but the malloc by the system.As you know, we can also use calloc().In the APIs of apr,we can use apr_pcalloc() like calloc(),apr_pcalloc() returns a zero-cleard memory chunk.If you use malloc/calloc, you need to call free() for the allocated memories.In contrast,you don’t need to free each memory chunks in memory pool.You just call apr_pool_destory() for the memory pool and it frees all the memory chunks.

   When we use apr_palloc() to allocate memory chunk,there is no limitation about memory chunk si-

ze. But it isn’t a good idea to allocate large size memory chunk in memory pool. That is because memo

ry pool is essentially designed for smaller chunks.Actually, the initial size of memory pool is 8 kilo byt

es.If you need a large size memory chunk,you should not use memory pool,but you should use malloc /

calloc.

Apr_pool_clearn and apr_pool_destroy

apr_pool_clear() is similar to apr_pool_destroy(), but the memory pool is still reusable. A typical code is as follows:

/* sample code about apr_pool_clear() */

apr_pool_t *mp;

apr_pool_create(&mp, NULL);

for (i = 0; i < n; ++i) {

    do_operation(..., mp);

    apr_pool_clear(mp);

}

apr_pool_destroy(mp);

The memory pool is used in do_operation(), that is, several memory chunks are allocated. If you don't need the memory chunks out of do_operation(), you can call apr_pool_clear(). You are able to reduce the amount of memory usage. If you are familiar with local stack memory system, you can think of memory pool as local stack memory. Calling apr_palloc() is similar to moving SP(stack pointer), and calling apr_pool_clear() is similar to rewinding SP. Both are very light operations.

 

Delegate or hook function

Apr_pool_cleanup_register and arp_pool_cleanup_kill

By apr_pool_cleanup_register(), we can have hook functions on memory pool clear/destroy. You have a callback function that is called whenever the memory pool is cleared or destroyed. In the callback functions, you can implement any finalization code depending on the memory pool. A typical code is as follows:

….

Int *value = (int *)malloc(sizeof(int));

Apr_pool_cleanup_register(my_pool,value,free,apr_pool_cleanup_null);

Using the way,we need not take care of whether the memory chunk is free.

when apr_pool_destory(my_pool) is called,the value is automatic freed.

someone want to obvious free the vaule again. You can kill the delegate with the apr_pool_cleanup_kill(my_pool,value,free).as follow:

Int *value = (int *)malloc(sizeof(int));

Apr_pool_cleanup_register(my_pool,value,free,apr_pool_cleanup_null);

Free(value);

apr_pool_cleanup_kill(my_pool,value,free);

 

/**

  * Register a function to be called when a pool is cleared or destroyed

  * @param p The pool register the cleanup with

  * @param data The data to pass to the cleanup function.

  * @param plain_cleanup The function to call when the pool is cleared

  *                      or destroyed

  * @param child_cleanup The function to call when a child process is about

  *                      to exec - this function is called in the child, obviously!

  */

APR_DECLARE(void) apr_pool_cleanup_register(

    apr_pool_t *p,

    const void *data,

    apr_status_t (*plain_cleanup)(void *),

apr_status_t (*child_cleanup)(void *));

 

 

/**

  * Register a function to be called when a pool is cleared or destroyed.

  *

  * Unlike apr_pool_cleanup_register which register a cleanup

  * that is called AFTER all subpools are destroyed this function register

  * a function that will be called before any of the subpool is destoryed.

  *

  * @param p The pool register the cleanup with

  * @param data The data to pass to the cleanup function.

  * @param plain_cleanup The function to call when the pool is cleared

  *                      or destroyed

  */

APR_DECLARE(void) apr_pool_pre_cleanup_register(

    apr_pool_t *p,

    const void *data,

    apr_status_t (*plain_cleanup)(void *));

 

 

/**

  * Remove a previously registered cleanup function.

  *

  * The cleanup most recently registered with @a p having the same values of

  * @a data and @a cleanup will be removed.

  *

  * @param p The pool to remove the cleanup from

  * @param data The data of the registered cleanup

  * @param cleanup The function to remove from cleanup

  * @remarks For some strange reason only the plain_cleanup is handled by this

  *          function

  */

APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data,

                                        apr_status_t (*cleanup)(void *));

 

 

/**

  * Replace the child cleanup function of a previously registered cleanup.

  *

  * The cleanup most recently registered with @a p having the same values of

  * @a data and @a plain_cleanup will have the registered child cleanup

  * function replaced with @a child_cleanup.

  *

  * @param p The pool of the registered cleanup

  * @param data The data of the registered cleanup

  * @param plain_cleanup The plain cleanup function of the registered cleanup

  * @param child_cleanup The function to register as the child cleanup

  */

APR_DECLARE(void) apr_pool_child_cleanup_set(

    apr_pool_t *p,

    const void *data,

    apr_status_t (*plain_cleanup)(void *),

apr_status_t (*child_cleanup)(void *));

 

 

/**

  * An empty cleanup function.

  *

  * Passed to apr_pool_cleanup_register() when no cleanup is required.

  *

  * @param data The data to cleanup, will not be used by this function.

  */

APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data);

Sub pool

The last topic about memory pool is sub pool. Each memory pool is able to have a parent memory pool. Accordingly, memory pools construct trees. The second argument of apr_pool_create() is a parent memory pool. When you pass NULL as the parent memory pool, the newly created memory pool becomes a root memory pool. You can create sub memory pools under the root memory pool. Whene you call apr_pool_destroy() for a memory pool in the tree, the child memory pools are also destroyed. When you call apr_pool_clear() for the memory pool, the memory pool is alive but the child memory pools are destroyed. Whenever a child memory pool is destroyed, the cleanup functions for it mentioned above are called.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值