当前位置: 首页 > news >正文

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_array_push

ngx_array_push

 声明在 src\core\ngx_array.h

void *ngx_array_push(ngx_array_t *a);

实现在 src\core\ngx_array.c

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, 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_array_push 函数的主要作用是向动态数组中添加一个新元素,并返回该元素的地址。

如果数组已满,则会尝试扩展数组容量。

函数签名 
void *ngx_array_push(ngx_array_t *a)

参数

a 是一个指向动态数组的指针。

返回值

返回一个指向新元素的指针。如果内存分配失败,则返回 NULL

定义局部变量 
void        *elt, *new;
size_t       size;
ngx_pool_t  *p;

elt :用于存储新元素的地址。

new :用于存储新分配的数组地址(如果需要扩容)。

size :当前数组占用的总内存大小。

p :指向数组的内存池。

这些变量将在后续代码中使用。

检查数组是否已满 
if (a->nelts == a->nalloc) {
    /* the array is full */
    ...
}

如果 nelts 等于 nalloc,说明数组已满,无法直接添加新元素,需要进行扩容操作。

计算当前数组的总大小 
size = a->size * a->nalloc;

size 表示当前数组占用的总内存大小,等于单个元素的大小乘以数组容量。

获取内存池指针
p = a->pool;

将数组的内存池指针赋值给局部变量 p,方便后续操作。

检查是否可以直接扩展数组 
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++;
}

这段代码检查两个条件:

当前数组是否是内存池中最后一个分配的内存块((u_char *) a->elts + size == p->d.last),意味着当前数组占用的空间就在当前这个块中

内存池的当前这个块是否有足够的剩余空间来扩展数组(p->d.last + a->size <= p->d.end)。

如果满足这两个条件,说明可以直接在内存池中扩展数组:

将内存池的 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;
}

如果无法直接扩展数组,则需要分配一块新的内存:

调用 ngx_palloc 函数,从内存池中分配两倍于当前数组大小的内存(2 * size

如果分配失败,返回 NULL

使用 ngx_memcpy 将原数组的内容复制到新分配的内存中。

更新数组的 elts 指针和容量(a->nalloc *= 2)。

这种方式通过加倍扩容策略,减少了频繁分配内存的开销。

计算并返回新元素的地址
elt = (u_char *) a->elts + a->size * a->nelts;
a->nelts++;
return elt;

计算新元素的地址:

(u_char *) a->elts + a->size * a->nelts 表示当前数组末尾的位置。

增加数组的元素计数(a->nelts++)。

返回新元素的地址。

相关文章:

  • MySQL后端返回给前端的时间变了(时区问题)
  • 【Qt学习】| 如何使用QVariant存储自定义类型
  • Web Worker终极优化指南:4秒卡顿→0延迟的实战蜕变
  • PTA:有序顺序表的插入
  • SSH无密登录配置
  • 2012年IMO几何预选题第6题
  • 《游戏人工智能编程 案例精粹》阅读心得
  • PHP课程预约小程序源码
  • sprintf和sscanf的用法和区别
  • Debezium系列之:记录一次源头数据库刷数据,造成数据丢失的原因
  • RoboBERT:减少大规模数据与训练成本,端到端多模态机器人操作模型(西湖大学最新)
  • MySQL-慢SQL解析及调试分析思路
  • go channel 的用法和核心原理、使用场景
  • JUC并发—10.锁优化与锁故障
  • Spring Boot (maven)分页4.0.2版本 专业版- 模板化最终版(测试)
  • java多线程及线程池
  • Web自动化中Selenium下Chrome与Edge的Webdriver常用Options参数
  • 鸿蒙app 开发中 对于数组方法 filter 的理解
  • 洛谷B3629
  • C#初级教程(7)——初级期末检测
  • 深圳中院回应“退休夫妻月入1.2万负债1.2亿”:其自述因经营不善负债
  • 体坛联播|安切洛蒂执掌巴西男足,字母哥尝试离开雄鹿
  • 技术派|更强的带刀侍卫:从054B型战舰谈谈世界护卫舰发展
  • 济南市委副秘书长吕英伟已任历下区领导
  • 最美西游、三星堆遗址等入选“2025十大年度IP”
  • 国际博物馆日中国主会场确定,北京将展“看·见殷商”等展览