• Nginx内存池(申请内存过程,小块内存分配)


    Nginx内存池(小块内存分配过程)

    Nginx申请内存函数有如下几个:

    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);
    }
    
    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);
    }
    
    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
    • 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

    其中ngx_palloc函数是考虑内存对齐的,而ngx_pnalloc是不考虑内存对齐的,ngx_pcalloc调用的还是ngx_palloc,只是对一个初始化为0的一个操作,主要分析的是ngx_palloc函数。

    参数size是申请内存块的大小,如果size大于小块内存分配的上限,申请的就是大块内存,否则申请的就是小块内存。

    小块内存申请过程

    先看小块内存的申请过程,ngx_palloc_small函数的定义:

    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;
    
        do {
            m = p->d.last;
    
            if (align) {
                m = ngx_align_ptr(m, NGX_ALIGNMENT);
            }
    
            if ((size_t) (p->d.end - m) >= size) {
                p->d.last = m + size;
    
                return m;
            }
    
            p = p->d.next;
    
        } while (p);
    
        return ngx_palloc_block(pool, size);
    }
    
    • 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

    在这里插入图片描述在这里插入图片描述
    首先用p指向分配小块内存的当前块,如果考虑字节对齐的话,会把p->d.last提升到NGX_ALIGNMENT的整数倍,NGX_ALIGNMENT是一个跟平台相关的宏,32位系统下是4,64位下是8,需要注意的是不是把申请的内存提升,而是把可用内存的起始地址提升,没有全部利用内存池的全部空间。
    如果提升后的可用大小大于申请的空间,把p->d.last = m + size;,m 返回即可。

    如果当前内存池块的可用大小不足,就回去下个内存块去找。如果已有的内存块都不满足,就会通过ngx_palloc_block函数再申请一个内存池块,提供使用。ngx_palloc_block函数除了申请新的内存块,还有一些维护内存池高性能的一些额外操作,函数定义如下:

    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);
    
        m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
        if (m == NULL) {
            return NULL;
        }
    
        new = (ngx_pool_t *) m;
    
        new->d.end = m + psize;
        new->d.next = NULL;
        new->d.failed = 0;
    
        m += sizeof(ngx_pool_data_t);
        m = ngx_align_ptr(m, NGX_ALIGNMENT);
        new->d.last = m + size;
    
        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;
    
        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

    ngx_palloc_block申请的新内存池块的头部信息不在是用ngx_pool_t 维护,而是用ngx_pool_data_t来维护,ngx_pool_data_t的结构比ngx_pool_t小,它的成员足以维护额外内存池块,可以省出更多的空间使用,申请的大小和头部块的大小一致。
    把需要维护的成员更新后,会对前面的块记录申请失败且需要开新块的次数+1,如果需要开新块的次数超过4次,说明这个块剩余的内存已经很小了,那么这块内存块就不再参与分配,把pool->current改为下个内存池块。
    最后再把新申请的内存池块串到next指针下。

    在这里插入图片描述

    最后最后需要注意:Nginx内存池分配的小块内存,是不提供回收释放的!

  • 相关阅读:
    Nginx日志有哪些常用的分析
    闲话Python编程-类
    输入操作符重载(读写文件)
    hive 任务日期设置(分区和业务日期)
    systemverilog中输入输出系统任务和函数(三)——Memory 加载和下载任务
    野火i.MX6ULL开发板wifi连接、SHH登录玄学篇
    高企申报需要的专利数量是多少?
    uniapp生成自定义(分享)图片并保存到相册
    备忘录模式-撤销功能的实现
    Bigemap在土地规划行业是怎么应用的?
  • 原文地址:https://blog.csdn.net/weixin_43973403/article/details/126091559