当前位置:K88软件开发文章中心网站服务器框架nginx → 文章内容

Nginx 基本数据结构

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-23 14:28:43

C 的释放是在最后一起发生的,也就是在使用完 C 以后。诚然,这在客观上增加了程序在一段时间的资源使用量。但是这也减轻了程序员分别管理三个资源的生命周期的工作。这也就是有所得,必有所失的道理。实际上是一个取舍的问题,要看在具体的情况下,你更在乎的是哪个。可以看一下在 Nginx 里面一个典型的使用 ngx_pool_t 的场景,对于 Nginx 处理的每个 http request, Nginx 会生成一个 ngx_pool_t 对象与这个 http request 关联,所有处理过程中需要申请的资源都从这个 ngx_pool_t 对象中获取,当这个 http request 处理完成以后,所有在处理过程中申请的资源,都将随着这个关联的 ngx_pool_t 对象的销毁而释放。ngx_pool_t 相关结构及操作被定义在文件src/core/ngx_palloc.h|c中。 typedef struct ngx_pool_s ngx_pool_t; struct ngx_pool_s { ngx_pool_data_t d; size_t max; ngx_pool_t *current; ngx_chain_t *chain; ngx_pool_large_t *large; ngx_pool_cleanup_t *cleanup; ngx_log_t *log; };从 ngx_pool_t 的一般使用者的角度来说,可不用关注 ngx_pool_t 结构中各字段作用。所以这里也不会进行详细的解释,当然在说明某些操作函数的使用的时候,如有必要,会进行说明。下面我们来分别解释下 ngx_pool_t 的相关操作。 ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);创建一个初始节点大小为 size 的 pool,log 为后续在该 pool 上进行操作时输出日志的对象。 需要说明的是 size 的选择,size 的大小必须小于等于 NGX_MAX_ALLOC_FROM_POOL,且必须大于 sizeof(ngx_pool_t)。 选择大于 NGX_MAX_ALLOC_FROM_POOL 的值会造成浪费,因为大于该限制的空间不会被用到(只是说在第一个由 ngx_pool_t 对象管理的内存块上的内存,后续的分配如果第一个内存块上的空闲部分已用完,会再分配的)。 选择小于 sizeof(ngx_pool_t)的值会造成程序崩溃。由于初始大小的内存块中要用一部分来存储 ngx_pool_t 这个信息本身。当一个 ngx_pool_t 对象被创建以后,该对象的 max 字段被赋值为 size-sizeof(ngx_pool_t)和 NGX_MAX_ALLOC_FROM_POOL 这两者中比较小的。后续的从这个 pool 中分配的内存块,在第一块内存使用完成以后,如果要继续分配的话,就需要继续从操作系统申请内存。当内存的大小小于等于 max 字段的时候,则分配新的内存块,链接在 d 这个字段(实际上是 d.next 字段)管理的一条链表上。当要分配的内存块是比 max 大的,那么从系统中申请的内存是被挂接在 large 字段管理的一条链表上。我们暂且把这个称之为大块内存链和小块内存链。 void *ngx_palloc(ngx_pool_t *pool, size_t size); 从这个 pool 中分配一块为 size 大小的内存。注意,此函数分配的内存的起始地址按照 NGX_ALIGNMENT 进行了对齐。对齐操作会提高系统处理的速度,但会造成少量内存的浪费。 void *ngx_pnalloc(ngx_pool_t *pool, size_t size); 从这个 pool 中分配一块为 size 大小的内存。但是此函数分配的内存并没有像上面的函数那样进行过对齐。.. code:: cvoid *ngx_pcalloc(ngx_pool_t *pool, size_t size);该函数也是分配size大小的内存,并且对分配的内存块进行了清零。内部实际上是转调用ngx_palloc实现的。 void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);按照指定对齐大小 alignment 来申请一块大小为 size 的内存。此处获取的内存不管大小都将被置于大内存块链中管理。 ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);对于被置于大块内存链,也就是被 large 字段管理的一列内存中的某块进行释放。该函数的实现是顺序遍历 large 管理的大块内存链表。所以效率比较低下。如果在这个链表中找到了这块内存,则释放,并返回 NGX_OK。否则返回 NGX_DECLINED。由于这个操作效率比较低下,除非必要,也就是说这块内存非常大,确应及时释放,否则一般不需要调用。反正内存在这个 pool 被销毁的时候,总归会都释放掉的嘛! ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size); ngx_pool_t 中的 cleanup 字段管理着一个特殊的链表,该链表的每一项都记录着一个特殊的需要释放的资源。对于这个链表中每个节点所包含的资源如何去释放,是自说明的。这也就提供了非常大的灵活性。意味着,ngx_pool_t 不仅仅可以管理内存,通过这个机制,也可以管理任何需要释放的资源,例如,关闭文件,或者删除文件等等。下面我们看一下这个链表每个节点的类型: typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t; typedef void (*ngx_pool_cleanup_pt)(void *data); struct ngx_pool_cleanup_s { ngx_pool_cleanup_pt handler; void *data; ngx_pool_cleanup_t *next; };data: 指明了该节点所对应的资源。 handler: 是一个函数指针,指向一个可以释放 data 所对应资源的函数。该函数只有一个参数,就是 data。 next: 指向该链表中下一个元素。看到这里,ngx_pool_cleanup_add 这个函数的用法,我相信大家都应该有一些明白了。但是这个参数 size 是起什么作用的呢?这个 size 就是要存储这个 data 字段所指向的资源的大小,该函数会为 data 分配 size 大小的空间。比如我们需要最后删除一个文件。那我们在调用这个函数的时候,把 size 指定为存储文件名的字符串的大小,然后调用这个函数给 cleanup 链表中增加一项。该函数会返回新添加的这个节点。我们然后把这个节点中的 data 字段拷贝为文件名。把 hander 字段赋值为一个删除文件的函数(当然该函数的原型要按照 void (\*ngx_pool_cleanup_pt)(void \*data))。 void ngx_destroy_pool(ngx_pool_t *pool);该函数就是释放 pool 中持有的所有内存,以及依次调用 cleanup 字段所管理的链表中每个元素的 handler 字段所指向的函数,来释放掉所有该 pool 管理的资源。并且把 pool 指向的 ngx_pool_t 也释放掉了,完全不可用了。 void ngx_reset_pool(ngx_pool_t *pool);该函数释放 poo

上一页  [1] [2] [3] [4] [5] [6] [7] [8] [9]  下一页


Nginx 基本数据结构