Ubuntu 下 nginx-1.24.0 源码分析 - ngx_array_push

news/2025/2/23 11:18:09

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++)。

返回新元素的地址。


http://www.niftyadmin.cn/n/5863365.html

相关文章

C#初级教程(5)——解锁 C# 变量的更多奥秘:从基础到进阶的深度指南

一、变量类型转换&#xff1a;隐式与显式的门道 &#xff08;一&#xff09;隐式转换&#xff1a;编译器的 “贴心小助手” 隐式转换是编译器自动进行的类型转换&#xff0c;无需开发者手动干预。这种转换通常发生在将取值范围小的数据类型赋值给取值范围大的数据类型时&#…

力扣hot100刷题——0~10

文章目录 1.两数之和题目描述思路一&#xff1a;哈希代码思路二&#xff1a;暴力代码 2.字母异位词分组题目描述思路&#xff1a;哈希(待改进)代码 3.最长连续序列题目描述思路&#xff1a;排序code 4.移动零题目描述思路&#xff1a;双指针code 5.盛最多水的容器题目描述思路&…

编程考古-忘掉它,Delphi 8 for the Microsoft .NET Framework

忘掉它吧&#xff0c;作一篇记录&#xff01; 【圣何塞&#xff0c;加利福尼亚 – 2003年11月3日】在今日的Borland开发者大会上&#xff0c;Borland正式推出了Delphi 8 for Microsoft .NET Framework。这款新版本旨在为Delphi开发者提供一个无缝迁移路径&#xff0c;将现有的…

c++贪心系列

各位小伙伴们新年好呀&#xff0c;这是年后的第一篇文章&#xff0c;那么还是一样&#xff0c;我们继续学习这个贪心算法。 第一题 题目链接 2418. 按身高排序 - 力扣&#xff08;LeetCode&#xff09; 题目解析 代码原理 方法一 1.先创建一个下标数组&#xff0c;将两个数…

算法很美笔记(Java)——动态规划

解重叠子问题&#xff08;当前解用到了以前求过的解&#xff09; 形式&#xff1a;记忆型递归或递推&#xff08;dp&#xff09; 动态规划本质是递推&#xff0c;核心是找到状态转移的方式&#xff0c;也就是填excel表时的逻辑&#xff08;填的方式&#xff09;&#xff0c;而…

[MDM 2024]Spatial-Temporal Large Language Model for Traffic Prediction

论文网址&#xff1a;[2401.10134] Spatial-Temporal Large Language Model for Traffic Prediction 论文代码&#xff1a;GitHub - ChenxiLiu-HNU/ST-LLM: Official implementation of the paper "Spatial-Temporal Large Language Model for Traffic Prediction" …

3damx 发动机活塞运动动画

使用HD解算器绑定&#xff1a;点(绑定的最终目标对象)→曲柄→活塞&#xff08;子控父&#xff0c;反向解算&#xff09; 点:绑定到轮子上的连接点

C语言:什么是动态内存管理?

动态内存管理是指在程序运行期间&#xff0c;根据实际需要动态地分配和释放内存空间的过程。与静态内存分配在编译时就确定内存大小不同&#xff0c;动态内存管理允许程序在运行时根据具体情况灵活地申请和释放内存。 主要通过 malloc 、 calloc 、 realloc 和 free 函数来实现…