Apache内存池内幕(7)[1]

[入库:2006年2月23日] [更新:2007年3月24日]

本文简介:

2.4.5内存池的销毁
由于Apache中所有的内存都来自内存池,因此当内存池被销毁的时候,所有从内存池中分配的空间都将受到直接的影响——被释放。但是不同的数据类型可能导致不同的释放结果,目前Apache中支持三种不同的数据类型的释放:
1)、普通的字符串数据类型
这类数据类型是最简单的数据类型,对其释放可以直接调用free而不需要进行任何的多余的操作
2)、带有析构功能的数据类型
这类数据类型类似于C++中的对象。除了调用free释放之外还需要进行额外的工作,比如apr_socket_t结构,它是与套接字的描述结构,除了释放该结构之外,还必须close套接字。
3)、进程数据类型
APR中的进程数据类型用结构apr_proc_t进行描述,当然它的分配内存也来自内存池。通常一个apr_proc_t对应一个正在运行的进程,因此从内存池中释放apr_proc_t结构的时候必然影响到正在运行的进程,如果处理释放和进程的关系是内存释放的时候必须考虑的问题。
下面我们详细描述每一个中内存销毁策略
2.4.5.1 带有析构功能的数据类型的释放
Apache2.0内存池中目前存放的数据种类非常繁多,既包括最普通的字符串,又包含各种复杂的数据类型,比如套接字、进程和线程描述符、文件描述符、甚至还包括各种复杂的自定义数据类型。事实上这是必然的结果。Apache中倡导一切数据都尽量从内存池中分配,而实际需要的数据类型则千变万化,因此内存池中如果出现下面的内存布局则不应该有任何的惊讶:

在上面的图示中,从内存池中分配内存的类型包括apr_bucket_brigade,apr_socket_t,apr_file_t等等。一个很明显而且必须解决的问题就是如何释放这些内存。当内存池被释放的时候,内存池中的各种数据结构自然也就被释放,这些都很容易就可以实现,比如free(apr_socket_t)、free(apr_dir_t)。不过有的时候情况并不是这么简单。比如对于apr_socket_t,除了释放apr_socket_t结构之外,更重要的是必须关闭该socket。这种情况对于apr_file_t也类似,除了释放内存外,还必须关闭文件描述符。这项工作非常类似于对象的释放,除了释放对象本身的空间,还需要调用对象的析构函数进行资源的释放。
因此正确的资源释放方式必须是能够识别内存池中的数据类型,在释放的时候完成与该类型相关的资源的释放工作。某一个数据结构除了调用free释放它的空间之外,其余的应该采取的释放措施用数据结构cleanup_t描述,其定义如下:
struct cleanup_t {
struct cleanup_t *next;
const void *data;
apr_status_t (*plain_cleanup_fn)(void *data);
apr_status_t (*child_cleanup_fn)(void *data);
};
该数据结构通常简称为清除策略数据结构。每一个结构对应一个处理策略,Apache中允许一个数据类型对应多个策略,各个处理策略之间通过next形成链表。data则是清除操作需要的额外的数据,由于数据类型的不确定性,因此只能定义为void*,待真正需要的时候在进行强制类型转换,通常情况下,该参数总是为当前操作的数据类型,因为清除动作总是与具体类型相关的。另外两个成员则是函数指针,指向真正的清除操作函数。child_cleanup_fn用于清除该内存池的子内存池,plain_cleanup_fn则是用于清除当前的内存池。
为了能够在释放的时候调用对应的处理函数,首先必须在内存池中注册指定类型的处理函数。注册使用函数apr_pool_cleanup_register,注册函数原型如下:
APR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *p, const void *data,
                      apr_status_t (*plain_cleanup_fn)(void *data),
                      apr_status_t (*child_cleanup_fn)(void *data))
p是需要注册cleanup函数的内存池,当p被释放时,所有的cleanup函数将被调用。Data是额外的数据类型,通常情况下是注册的数据类型,plain_cleanup_fn和child_cleanup_fn的含义与cleanup_t结构中对应成员相同,因此假如需要在全局内存池pglobal中注册类型apr_socket_t类型变量sock的处理函数为socket_cleanup,则注册过程如下:
apr_pool_cleanup_register(pglobal,(void*)sock,socket_cleanup,NULL);
    cleanup_t *c;
    if (p != NULL) {
        if (p->free_cleanups) {
            c = p->free_cleanups;
            p->free_cleanups = c->next;
        } else {
            c = apr_palloc(p, sizeof(cleanup_t));
        }
        c->data = data;
        c->plain_cleanup_fn = plain_cleanup_fn;
        c->child_cleanup_fn = child_cleanup_fn;

本文关键:Apache内存池内幕(7)
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top