Nginx基础. Nginx数组与链表
2015-08-29 19:43
501 查看
ngx_array_t
实现文件: ./src/core/ngx_array.h ./src/core/ngx_array.c
1. 数据结构定义
2. 数组操作
3. 操作详解
关于数组的操作, 大多简单. 只拿出几个谈谈
先看的当然是数组的创建函数, 但是它就是简单的内存分配以及变量初始化, 这里就不贴出来了
下面是数组的销毁动作, 主要就是修改了内存池的last指针, 并没有调用free等释放内存的操作,显然,这种维护效率是很高的。
最后, 看看如何添加一个数组元素
根据之前学习STL的经验, 如果当前元素超过了最大元素个数, 那么就会重新分配一段内存给这个数组
ngx_list_t
链表是Nginx封装的链表容器, 它在Nginx中使用的非常频繁.
相比较libevent中的TAILQ队列, Nginx中的list理解起来要容易的多
下面就简单的认识一下这个链表.
1. 数据结构的定义
要注意的是, ngx_list_t不是一个单纯的链表, 它是存储数组的链表, 即每个链表元素ngx_list_part_t是一个数组, 拥有连续的内存
该数组既依赖ngx_list_t结构中的size和nalloc来表示数组的容量, 同时又依靠每个ngx_list_part_t成员中的nelts来表示当前已经使用了多少容量.
对于这样的设计, 有什么好处呢?
1. 链表中存储的元素是灵活的, 可以是任何一种数据结构
2. 链表元素需要占用的内存由ngx_list_t管理, 它已经通过数组分配好了
3. 小块的内存使用链表访问是低效率的, 使用数组偏移来访问则高效的多
2. 链表的操作
除了初始化, 还有一个要看的就是插入元素了
既然链表的每个元素是数组, 那么新值插入的位置就是最后一个数组元素的末尾, 或是另开一个链表元素来装这个值
实现文件: ./src/core/ngx_array.h ./src/core/ngx_array.c
1. 数据结构定义
typedef struct { void *elts; //数组数据区起始位置 ngx_uint_t nelts; //当前存放元素个数 size_t size; //存放的每个元素的大小 ngx_uint_t nalloc; //数组最大能存放的元素个数 ngx_pool_t *pool; //使用的内存池对象 } ngx_array_t;单纯的从结构定义可以看出, 数组是与内存池绑定的, 占用的空间由内存池分配
2. 数组操作
1.)创建 ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size); 2.) 初始化 static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size); 3.) 销毁 void ngx_array_destroy(ngx_array_t *a); 4.) 加入元素 void *ngx_array_push(ngx_array_t *a); 5.) 加入n个相同元素 void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
3. 操作详解
关于数组的操作, 大多简单. 只拿出几个谈谈
先看的当然是数组的创建函数, 但是它就是简单的内存分配以及变量初始化, 这里就不贴出来了
下面是数组的销毁动作, 主要就是修改了内存池的last指针, 并没有调用free等释放内存的操作,显然,这种维护效率是很高的。
void ngx_array_destroy(ngx_array_t *a) { ngx_pool_t *p; p = a->pool; //下面是对数组内容和其结构的"删除", 实际上只是指针的移动. 如果正巧他们不是正好在last指针前面, 那么也就不管了, 反正内存是统一管理的 if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) { p->d.last -= a->size * a->nalloc; } if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) { p->d.last = (u_char *) a; } }
最后, 看看如何添加一个数组元素
根据之前学习STL的经验, 如果当前元素超过了最大元素个数, 那么就会重新分配一段内存给这个数组
void * ngx_array_push(ngx_array_t *a) { void *elt, *new; size_t size; ngx_pool_t *p; //如果这段数组内存还可以存的下新的元素, 那么处理就简单了 if (a->nelts == a->nalloc) { /* the array is full */ //首先size得到原来数组的大小 size = a->size * a->nalloc; p = a->pool; //判断last指针是否正好在这段数组内存的后面, 如果正好, 那么我们继续判断是否接下来还有空间可以存数组元素 //这里就跟STL里的vector不同了. 因为我们是在内存池里操作, 如果发现这段数组内存后面正好还有空余的, 那么就直接利用把, 省的再繁杂的操作 if ((u_char *) a->elts + size == p->d.last && p->d.last + a->size <= p->d.end) { /* * the array allocation is the last in the pool * and there is space for new allocation */ p->d.last += a->size; //因为这里是在原有数组已满的基础上添加元素,又正好有这段内存, 所以需要修改最大元素存储的数量 a->nalloc++; } else { /* allocate a new array */ //否则的话, 只能老老实实的分配一段新的内存, 且大小是原来的两倍 new = ngx_palloc(p, 2 * size); if (new == NULL) { return NULL; } //将原来的元素都复制过来 ngx_memcpy(new, a->elts, size); a->elts = new; a->nalloc *= 2; } } //将新元素需要的内存返回 elt = (u_char *) a->elts + a->size * a->nelts; a->nelts++; return elt; }
ngx_list_t
链表是Nginx封装的链表容器, 它在Nginx中使用的非常频繁.
相比较libevent中的TAILQ队列, Nginx中的list理解起来要容易的多
下面就简单的认识一下这个链表.
1. 数据结构的定义
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; }; typedef struct { ngx_list_part_t *last; //指向链表最后一个节点 ngx_list_part_t part; //链表头中包含的第一个节点(part) size_t size; //虽然存储的类型是任意的, 但还是要通过size来限制每个元素占用的空间大小, 即数组中元素大小必须小于或等于size ngx_uint_t nalloc; //链表的数组元素一旦分配后是不可更改的. nalloc表示每个数组容量 ngx_pool_t *pool; } ngx_list_t;ngx_list_t描述整个链表, 而ngx_list_part_t只描述链表的一个元素.
要注意的是, ngx_list_t不是一个单纯的链表, 它是存储数组的链表, 即每个链表元素ngx_list_part_t是一个数组, 拥有连续的内存
该数组既依赖ngx_list_t结构中的size和nalloc来表示数组的容量, 同时又依靠每个ngx_list_part_t成员中的nelts来表示当前已经使用了多少容量.
对于这样的设计, 有什么好处呢?
1. 链表中存储的元素是灵活的, 可以是任何一种数据结构
2. 链表元素需要占用的内存由ngx_list_t管理, 它已经通过数组分配好了
3. 小块的内存使用链表访问是低效率的, 使用数组偏移来访问则高效的多
2. 链表的操作
ngx_list_t * 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)); if (list == NULL) { return NULL; } if (ngx_list_init(list, pool, n, size) != NGX_OK) { return NULL; } return list; }在ngx_list_init中, 不仅初始化了一些变量, 还分配了 n*size 大小内存的一个数组. 说明最初创建的list会自带一个数组元素
除了初始化, 还有一个要看的就是插入元素了
既然链表的每个元素是数组, 那么新值插入的位置就是最后一个数组元素的末尾, 或是另开一个链表元素来装这个值
void * ngx_list_push(ngx_list_t *l) { void *elt; ngx_list_part_t *last; last = l->last; //如果我们要插入的那个数组已经满了 if (last->nelts == l->nalloc) { /* the last part is full, allocate a new list part */ //继续分配 last = ngx_palloc(l->pool, sizeof(ngx_list_part_t)); if (last == NULL) { return NULL; } last->elts = ngx_palloc(l->pool, l->nalloc * l->size); if (last->elts == NULL) { return NULL; } last->nelts = 0; last->next = NULL; //新的数组元素放在链表的末尾 l->last->next = last; l->last = last; } //返回新值要插入的空间起始地址 elt = (char *) last->elts + l->size * last->nelts; last->nelts++; return elt; }
相关文章推荐
- Nginx基础知识. Nginx内存池分析
- Linux下查看Nginx、Napache、MySQL、PHP的编译参数
- nginx缓存优先级
- 44_02 nginx
- Apache与Nginx的优缺点比较
- Nginx服务器读取不到文件的转换方法
- 04_Nginx命令行参数,控制信号,Nginx启动、停止、重启命令
- 04_Nginx命令行参数,控制信号,Nginx启动、停止、重启命令
- Nginx服务器配置指令
- Linux下最新版php5.6源码安装与apache/nginx集成教程
- 02_Nginx基本配置与参数说明 + 辅助命令
- 02_Nginx基本配置与参数说明 + 辅助命令
- Nginx防爬虫或限制浏览器访问
- nginx(1)
- Windows之安装Nginx、PHP、mysql
- NGINX开机自动启动
- 将树莓派变成一个web服务器(2):Nginx+Flask+uWSGI部署全过程
- Nginx + PHP mysql_pconnect = Database errors (Too many connections)
- nginx的安装与配置小结
- 安装成功的nginx如何添加未编译安装模块