栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

文章目录
  • 内存分配函数
    • 1. 考虑内存对齐版本
    • 2. 不考虑内存对齐版本
    • 3. 初始化为0的版本
  • 分配小块内存源码解读

内存分配函数

内存分配时考虑了小块和大块,用不同函数实现,
如果申请的空间大小 <= 当前内存池的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);
}

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);
}
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;
}
分配小块内存源码解读
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. 进入函数后先申请两个指针,一个是无符号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. 将last指针调节至 m + size的位置,因为这块内存就是要分配出去的。

  1. 该for()循环是从第一个内存池开始检查,检测 failed标记加一后是否大于4,如果大于4,直接让current指针指向下一个内存池的起始位置,意味着以后都不在这个failed > 4 的内存池申请空间了,因为只剩一点点空间或者不剩空间了。
  2. 让指针 p 的next域指向 new,即和下一块内存池连接起来。
  3. return m,由于last指针指向了 m + size的位置,那意味着返回的m 到 m + size这块空间就是客户需要的那一块内存。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/995161.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号