nginx源码初读(5)--让烦恼从数据结构开始(ngx_array)

数组的结构体定义:

typedef struct ngx_array_s       ngx_array_t;
struct ngx_array_s {
    void        *elts;           // 指向数组存储位置的首地址
    ngx_uint_t   nelts;          // 当前数组中已经存放的元素个数
    size_t       size;           // 数组中每个元素的大小
    ngx_uint_t   nalloc;         // 当前最多能容纳的元素个数,类似cpp中的Vector,当nelts大于nalloc时扩容
    ngx_pool_t  *pool;           // 该数组对应的内存池
};

下面介绍数组操作函数:

ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
/* 从pool中申请array结构体内存,并调用init初始化(申请n*size内存,改变array内的属性),
 * 所以元素与结构体内存可能并不连续,但肯定在同一个pool里,失败返回NULL */

void ngx_array_destroy(ngx_array_t *a);
/* 依次销毁数组的数据区和结构体内存,将内存返还给pool(last-=)
 * if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
       p->d.last = (u_char *) a;
   }
 * 销毁结构体的代码如上,因为这代码看起来很奇怪,它怎么知道数组肯定再pool的最后,没加过其他东西了?
   看了源码数组也并不是通过单独的pool来管理的,也就是说pool中还可能有很多其他的数据。
   在nginx整个代码中没有找到对ngx_array_destroy的引用
 */

void *ngx_array_push(ngx_array_t *a);
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n); 
/* 在数组a上新追加元素,并返回指向新元素的指针。需要把返回的指针转换为具体类型,
   然后再给新元素本身或者是各字段(如果数组的元素是复杂类型)赋值。*/

static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
/* 如果一个数组对象是被分配在堆上的,那么当调用ngx_array_destroy销毁以后,如果想再次使用,就可以调用此函数。
   如果一个数组对象是被分配在栈上的,那么就需要调用此函数,进行初始化的工作以后,才可以使用。*/

从以上代码中大家有没有发现一个很严肃的问题,不管是destroy还是扩容,源码中原来的内存位置都是没有free的,这样肯定造成了内存的浪费,nginx作者这么计较内存为什么会有这种问题呢,真心不理解,感觉很容易解决啊。不过肯定有理由把,我们在使用的时候最好提前规划好数组的大小,避免多次扩容造成的浪费。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章