大佬链接:http://blog.csdn.net/livelylittlefish/article/details/6599065
http://blog.csdn.net/livelylittlefish/article/details/6586946
ngx_list_t是nginx封装的链表容器
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s {
void *elts;//指向该节点实际的数据区
ngx_uint_t nelts;//该节点实际存放的元素个数
ngx_list_part_t *next;//指向下个节点
};//ngx_list_part_t
typedef struct {
ngx_list_part_t *last;//指向链表最后一个节点
ngx_list_part_t part;//链表的首个数组元素
size_t size;//每个实际存放元素大小
ngx_uint_t nalloc;//实际存放元素的个数
ngx_pool_t *pool;//指向该链表所分配的内存池首地址
} ngx_list_t;
//其中,sizeof(ngx_list_t)=28B,sizeof(ngx_list_part_t)=12B
由ngx_list_t结构体中的pool成员指向创建该ngx_list_t链表的内存池首地址,是什么意思?
是指ngx_list_t结构体存储在由pool指向的内存池中,因此,要在创建ngx_list_t前先创建pool指向的内存池。内存池的结构体如下:
typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
struct ngx_pool_cleanup_s {
ngx_pool_cleanup_pt handler;
void *data;
ngx_pool_cleanup_t *next;
};
typedef struct ngx_pool_large_s ngx_pool_large_t;
struct ngx_pool_large_s {
ngx_pool_large_t *next;
void *alloc;
};
typedef struct {
u_char *last;//指向ngx_pool_t结构体尾部
u_char *end;//指向创建的pool内存池尾部
ngx_pool_t *next;//指向下一个内存池,或为空
ngx_uint_t failed;//
} ngx_pool_data_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
其中,sizeof(ngx_pool_data_t)=16B,sizeof(ngx_pool_t)=40B
创建内存池(ngx_palloc.c):
ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)
{
ngx_pool_t *p;
p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
if (p == NULL) {
return NULL;
}
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
p->d.end = (u_char *) p + size;
p->d.next = NULL;
p->d.failed = 0;
size = size - sizeof(ngx_pool_t);
p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;//max最大不超过4095B?
p->current = p;
p->chain = NULL;
p->large = NULL;
p->cleanup = NULL;
p->log = log;
return p;
}
创建内存池例子:
ngx_pool_t *pool;
printf("create a new pool:\n");
pool = ngx_create_pool(1024, NULL);//创建一个内存池,容量为1024B
创建完pool,再创建链表容器:
ngx_list_t *list = ngx_list_create(pool, 5, sizeof(int));//分配5*sizeof(int)容量给list
ngx_list_create:
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
ngx_list_t *list;
list = ngx_palloc(pool, sizeof(ngx_list_t));//分配28B内存给ngx_list_t
if (list == NULL) {
return NULL;
}
if (ngx_list_init(list, pool, n, size) != NGX_OK) {//初始化链表,分配实际容量n*size给list
return NULL;
}
return list;
}
ngx_palloc:
void *
ngx_palloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
if (size <= pool->max) {//分配内存容量小于内存池实际容量
return ngx_palloc_small(pool, size, 1);
}
#endif
return ngx_palloc_large(pool, size);
}
ngx_palloc_small:
static ngx_inline void *
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
{
u_char *m;
ngx_pool_t *p;
p = pool->current;//内存池首地址
do {
m = p->d.last;//内存池实际容量首地址
if (align) {//对齐
m = ngx_align_ptr(m, NGX_ALIGNMENT);
}
if ((size_t) (p->d.end - m) >= size) {
p->d.last = m + size;//size为ngx_list_t被分配的内存池容量
return m;
}
p = p->d.next;
} while (p);
return ngx_palloc_block(pool, size);
}
http://blog.csdn.net/niitlcj/article/details/9311189
ngx_align_ptr:
#ifndef NGX_ALIGNMENT
#define NGX_ALIGNMENT sizeof(unsigned long) /* platform word */
#endif
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
#define ngx_align_ptr(p, a) \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
理解一下
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
a是2的幕(如NGX_ALIGNMENT),因此,a的二进制形式,假设第n位为1,因此第0~n-1位为0,高于n的位皆为0,即0…010…0。因此,a-1为0…001…1,~(a-1)为1…110…0。
(d)+(a-1)必然 >= a ,当d<=a时,(d)+(a-1)的第n位必然为1,所以&(~(a-1))后,为0…010…0,即a;当d>a时,((d)+(a-1)) & ~(a - 1)将会是a的整数k倍,且d<=k*a。因此,实现内存对齐。
这种计算地址或者长度对齐,取整的宏还是很有用的。cpu访问对齐的数据较快,不对齐的的int之类的,有可能区要多次内存访问才能取到值。
向上取整倍数,ngx_align内存对齐的宏,对于a,传入CPU的二级cache的line大小,通过ngx_cpuinf函数,可以获得ngx_cacheline_size的大小,一般intel为64或128
计算宏ngx_align(1, 64)=64,只要输入d<64,则结果总是64,如果输入d=65,则结果为128,以此类推。
ngx_list_init:
static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
list->part.elts = ngx_palloc(pool, n * size);
if (list->part.elts == NULL) {
return NGX_ERROR;
}
list->part.nelts = 0;
list->part.next = NULL;
list->last = &list->part;
list->size = size;
list->nalloc = n;
list->pool = pool;
return NGX_OK;
}
可以看到,ngx_list_init初始化ngx_list_t时,把n*size的内存池容量首地址放在part.elts中。