原文地址:http://blog.csdn.net/marcky/article/details/5747431

备注:以下关于Nginx源码的分析基于淘宝开源项目Tengine.

Nginx中对数组进行了封装,关于数组的源码定义位于tengine/src/core/ngx_array.c|h中。

Nginx中使用以下结构来维护数组:

  typedef struct {
void *elts;
ngx_uint_t nelts;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_array_t;

1. elts指向一块向系统申请的内存;在nginx中,这块内存是通过malloc或者其他类似操作从内存池中申请而来的。例如,在tengine/src/core/ngx_array.h中,通过如下语句对elts成员进行赋值:关于ngx_palloc函数的定义可以参考tengine/src/core/ngx_palloc.c.

array->elts = ngx_palloc(pool, n * size);

ngx_palloc的函数声明为:

void * ngx_palloc(ngx_pool_t *pool, size_t size);

2. nelts记录了数组中已存放元素的个数。

3. size是数组元素的大小,可以通过sizeof()求得。

4. nalloc是整个数组可存放元素的单元数。

5. pool当然就是内存池了,用其保存分配此数组的内存池地址。

通过对数组结构成员的了解,可以得之:elts所指的内存大小 = size * nalloc。

nginx给我们提供了5个接口函数,方便进行数组的操作,分别是:

ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);

此函数即是用来创建一个可以存储n个元素,每个元素大小为size的数组。返回值是维护数组的结构的地址。在ngx_array_create函数中同样会调用ngx_palloc函数进行存储空间的分配。

void ngx_array_destroy(ngx_array_t *a);

此函数顾名思义就是释放内存、销毁数组,但nginx并没有真正的释放内存,而是将内存归还给内存池(a->pool)。

void *ngx_array_push(ngx_array_t *a);

此函数的功能就是取得下一个可以存放元素的单元地址。由于nginx封装的数组可以根据需求动态扩展,所以此函数必须处理预分配的内存不足的情况。nginx在ngx_array_push函数内存采用了两种策略来动态增加内存。

  • 预分配的内存不足了,但数组所在的内存池槽还有可以分配一个元素的空闲内存,那就在数组末端分配一个元素的空间来暂时满足当前需求。
  • 预分配的内存不足,同时数组所在的内存池槽的空闲内存也不足以分配一个元素的空间了,那就向内存池申请一个原数组2倍大小的新内存空间,再将原数组复制到新的位置,最后返回下一个空闲元素位置给我们使用。
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 = a->size * a->nalloc; p = a->pool; 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, * size);
if (new == NULL) {
return NULL;
} ngx_memcpy(new, a->elts, size);
a->elts = new;
a->nalloc *= ;
}
}
elt = (u_char *) a->elts + a->size * a->nelts;
a->nelts++; return elt;
}

此接口函数是nginx模块开发中,使用最多的数组操作接口了,列举一个简单的使用例子:

typedef struct {
int age;
char *name;
} person_t;
person_t *p = ngx_array_push(a); /*a 是一个被创建的用来存放person_t类型元素的数组*/ //申请内存
p->age = ; //往内存中填充数据
p->name = (char *)"marcky";

nginx数组的用法就是先申请内存,然后再向内存中填充数据;这是俄罗斯大牛在整个nginx中的编码手法。

void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);  

从函数名也可以猜到它是用来获得n个元素的内存空间地址,然后从获得的地址向数组中填入n个元素。好像使用得比较少。此操作面临数组空间不足的时候,也是采用了类似ngx_array_push的两个动态增加内存的策略。但存在略微的不同之处。读源码可以了解到。

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_t  a;  /*定义数组a,但数组a只是一个维护数组的结构,还没有真正存放元素的内存空间,所以得初始化它。*/
ngx_array_init(&a, p, , sizeof(int) ); /*将数组初始化为可以存放10个整型元素的数组*/

Nginx源码分析--数组(转)的更多相关文章

  1. nginx源码分析——数组

    ngx_array.h /* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #ifndef _NGX_ARRAY_H_INCLU ...

  2. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  3. Nginx源码分析:3张图看懂启动及进程工作原理

    编者按:高可用架构分享及传播在架构领域具有典型意义的文章,本文由陈科在高可用架构群分享.转载请注明来自高可用架构公众号「ArchNotes」.   导读:很多工程师及架构师都希望了解及掌握高性能服务器 ...

  4. nginx源码分析线程池详解

    nginx源码分析线程池详解 一.前言     nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...

  5. nginx源码分析--使用GDB调试(strace、 pstack )

    nginx源码分析--使用GDB调试(strace.  pstack ) http://blog.csdn.net/scdxmoe/article/details/49070577

  6. nginx源码分析-源码结构

    本文主要简单介绍nginx源码目录结构.程序编译流程.如何构建学习nginx的环境等.本文以及后续nginx源码分析文章是基于nginx当前(2009-02-27)的稳定版本0.6.35进行的分析,该 ...

  7. nginx源码分析——configure脚本

    源码:nginx 1.13.0-release   一.前言      在分析源码时,经常可以看到类似 #if (NGX_PCRE) .... #endif 这样的代码段,这样的设计可以在不改动源码的 ...

  8. nginx源码分析之hash的实现

    nginx实现了自己的hash数据结构,正如数据结构中讲述的那样,nginx用开放链表法解决冲突,不过不同的是一旦一个hash表被初始化后就不会被修改,即插入和删除,只进行查询操作,所以nginx通过 ...

  9. [nginx] nginx源码分析--SNI性能分析

    概念 我们已经知道什么是SNI,以及如何为用户配置SNI. [nginx] nginx使用SNI功能的方法 问题 通过观察配置文件,可以发现,针对每一个SSL/TLS链接, nginx都会动态的查找( ...

随机推荐

  1. [codeforces464D]World of Darkraft - 2 概率期望

    D. World of Darkraft - 2 time limit per test 2 seconds memory limit per test 256 megabytes input sta ...

  2. [BZOJ4540][HNOI2016]序列 莫队

    4540: [Hnoi2016]序列 Time Limit: 20 Sec  Memory Limit: 512 MB Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n ...

  3. 使用oVal进行Java Bean 验证的注意事项

    如果需要不同条件验证不同的属性的时候,需要使用profiles属性,每个校验注解符中都有.注意:oVal默认是启用所有的profiles,所以在对单独一个profile进行启用的时候,需要先disab ...

  4. Mybatis笔记一:java.lang.NoClassDefFoundError: org/apache/ibatis/mapping/DatabaseIdProvider

    异常错误:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSess ...

  5. 【JavaScript】事件

    一.前言         继续上一章的内容,继续今天的Js学习. 二.内容         事件处理程序 事件就是用户或浏览器自身执行的某种动作.而响应某个事件的函数就叫做事件处理程序 //HTML事 ...

  6. 【BZOJ1566】【NOI2009】管道取珠(动态规划)

    [BZOJ1566][NOI2009]管道取珠(动态规划) 题面 BZOJ 题解 蛤?只有两档部分分.一脸不爽.jpg 第一档?爆搜,这么显然,爆搜+状压最后统计一下就好了 #include<i ...

  7. 扔几道sb题

    1.给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间. 你能求 ...

  8. BZOJ2212 [Poi2011]Tree Rotations 【线段树合并】

    题目链接 BZOJ2212 题解 一棵子树内的顺序不影响其与其它子树合并时的答案,这一点与归并排序的思想非常相似 所以我们只需单独处理每个节点的两棵子树所产生的最少逆序对即可 只有两种情况,要么正序要 ...

  9. 洛谷 P1278 单词游戏 【状压dp】

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  10. spark core (二)

    一.Spark-Shell交互式工具 1.Spark-Shell交互式工具 Spark-Shell提供了一种学习API的简单方式, 以及一个能够交互式分析数据的强大工具. 在Scala语言环境下或Py ...