• Nginx内存池:内存分配方案 | 小块内存分配方案


    内存分配函数

    内存分配时考虑了小块和大块,用不同函数实现,
    如果申请的空间大小 <= 当前内存池的max,调用ngx_palloc_small();
    否则调用 ngx_palloc_large()

    1. 考虑内存对齐版本

    
    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2. 不考虑内存对齐版本

    void *ngx_pnalloc(ngx_pool_t *pool, size_t size)
    {
    #if !(NGX_DEBUG_PALLOC)
        if (size <= pool->max) {
            return ngx_palloc_small(pool, size, 0);
        }
    #endif
    
        return ngx_palloc_large(pool, size);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3. 初始化为0的版本

    在ngx_pcalloc()函数中,依然是调用 ngx_palloc(),但会将申请的空间全部置为0.

    void *ngx_pcalloc(ngx_pool_t *pool, size_t size)
    {
        void *p;
    
        p = ngx_palloc(pool, size);
        if (p) {
            ngx_memzero(p, size);
        }
    
        return p;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    分配小块内存源码解读

    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;  // 1
    
        do {
            m = p->d.last;  // 2
    
            if (align) {	// 3
                m = ngx_align_ptr(m, NGX_ALIGNMENT);
            }
    
            if ((size_t) (p->d.end - m) >= size) { // 4
                p->d.last = m + size;
    
                return m;
            }
    
            p = p->d.next;  // 5
    
        } while (p);
    
        return ngx_palloc_block(pool, size);
    }
    
    static void *
    ngx_palloc_block(ngx_pool_t *pool, size_t size)
    {
        u_char      *m;
        size_t       psize;
        ngx_pool_t  *p, *new;
    
        psize = (size_t) (pool->d.end - (u_char *) pool); // 6
    
        m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);  // 7
        if (m == NULL) {
            return NULL;
        }
    
        new = (ngx_pool_t *) m; // 8
    
        new->d.end = m + psize;  // 9
        new->d.next = NULL;
        new->d.failed = 0;
    
        m += sizeof(ngx_pool_data_t);  // 10
        m = ngx_align_ptr(m, NGX_ALIGNMENT);  // 11
        new->d.last = m + size;  // 12
    	
    	// 13
        for (p = pool->current; p->d.next; p = p->d.next) {
            if (p->d.failed++ > 4) {
                pool->current = p->d.next;
            }
        }
    
        p->d.next = new;	// 14
    
        return m;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    1. 进入函数后先申请两个指针,一个是无符号char类型 m,一个是内存池类型的 p,先将p指向当前内存池pool的current,也就是内存池的开头:如图中p。

    在这里插入图片描述

    1. 进入do…while()循环,意味着不管循环条件是否满足,都要执行一遍do的语句,第2步让指针 m 指向 p的last,也就是内存池可分配内存的起始位置。

    在这里插入图片描述

    1. 判断参数align ,如果为真,需要进行内存对齐处理,否则不进行。
    2. 判断当前内存池可用空间是否大于等于 需要申请的空间size,如果满足条件,那么直接将last指针偏移 size个字节,返回 指针 m 即可。

    在这里插入图片描述在这里插入图片描述

    1. 如果上面的步骤没有返回,就让p指向下一个小块的内存池,但初始化时候next域设置成了NULL,所以循环退出了,需要执行下面的ngx_palloc_block()函数。
    2. 进入该函数,先计算内存池pool的总大小,赋值给 psize;
    3. 再次申请一个内存池,大小是 psize,并由 m指向该内存池起始位置。
    4. 让new指针指向m的位置。

    在这里插入图片描述

    1. 将这一块内存池的数据域初始化(end指向末尾,next置为NULL,failed置为0)。
    2. m指向该内存池可供使用的起始位置(偏移一个ngx_pool_data_t的字节个数)。

    在这里插入图片描述

    1. 将m调节至指定的倍数:宏定义如下
    #define ngx_align_ptr(p, a)                                                   \
        (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
    
    • 1
    • 2
    1. 将last指针调节至 m + size的位置,因为这块内存就是要分配出去的。

    在这里插入图片描述

    1. 该for()循环是从第一个内存池开始检查,检测 failed标记加一后是否大于4,如果大于4,直接让current指针指向下一个内存池的起始位置,意味着以后都不在这个failed > 4 的内存池申请空间了,因为只剩一点点空间或者不剩空间了。
    2. 让指针 p 的next域指向 new,即和下一块内存池连接起来。
    3. return m,由于last指针指向了 m + size的位置,那意味着返回的m 到 m + size这块空间就是客户需要的那一块内存。
  • 相关阅读:
    一种基于深度学习(卷积神经网络CNN)的人脸识别算法-含Matlab代码
    Vue学习之--------深入理解Vuex之模块化编码(2022/9/4)
    JavaScript-正则表达式
    7 种提升 Spring Boot 吞吐量神技
    【freertos】010-消息队列概念及其实现细节
    七星创客商业模式:享受优惠价格和丰厚奖励的新选择!
    java-php-python-ssm医院分诊管理系统计算机毕业设计
    热迁移中VirtIO-PCI设备的配置空间处理
    电脑系统重装后音频驱动程序怎么修复
    怎样在vue中隐藏el-form-item中的值、设置输入框的值是只读
  • 原文地址:https://blog.csdn.net/m0_56257585/article/details/125471020