Nginx内存管理及数据结构浅析–共享内存的实现
2015-11-02 16:08
911 查看
nginx是多进程模型,在许多场景我们可能需要跨进程共享数据,考虑到这个可能性,nginx本身也提供了共享内存这方面的接口。
ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);
这个是nginx中关于分配共享内存最底层的接口了,它实际上就是直接调用mmap进行共享内存的分配的。对于需要多次分配和释放共享内存的场景来说,直接用这个接口实际是无法忍受效率上的问题,或者有人想到可以直接分配一块大内存自己来进行分配释放的管理,但其实你不用自己做,nginx已经做好这部分的工作了,相关的接口是:
ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
通过这个接口我们可以分配一大块内存,再借助ngx_slab_pool_t这个结构体来管理共享内存。
那nginx又是如何来组织共享内存的呢?
在ngx_cycle_s结构里有一个成员,即ngx_cycle_s->shared_memory,它的类型是ngx_list_t,用来登记所有分配的共享内存,它装的节点类型是ngx_shm_zone_t,一个节点对应一块分配的共享内存,以下是它的源码:
我们再看看ngx_shared_memory_add这个函数的实现,它首先检查要分配的内存是否存在,存在则直接返回,否则创建一个新的再返回。
1. 两个相同名字的共享内存大小要一样。
2. 两个相同名字的共享内存tag要一样。
3. 如果当前共享内存已经存在,则不需要再次添加。会返回同一个共享内存
4. 如果此共享内存不存在,则添加一个新的ngx_shm_zone_t
添加完后会返回ngx_shm_zone_t,我们需要设置init函数和data数据
看到这里,会不会有一个疑问,ngx_shared_memory_add也就是找到或者插入一个ngx_shm_zone_t节点而已啊,但是并没有真正分配共享内存的操作啊?我刚开始也是百思不得其解,直到看到ngx_init_cycle这个函数后,才豁然开朗。
通过代码我们可以看到,对于每一个共享内存,都会先调用ngx_shm_alloc进行共享内存的分配,然后使用ngx_init_zone_pool对共享内存进行初始化,最后就调用我们设置的init函数了。
ngx_init_zone_pool主要的目的就是让我们可以通过slab来分配、释放内存(具体的用法这里暂不提及,以后有空可以专门写一篇文章来说)。下面我们来看看ngx_init_zone_pool的实现吧:
在调用这个接口进行初始化后,以后我们在这块共享内存上进行分配和释放都是通过slab来完成的了,例如有ngx_slab_alloc和
ngx_slab_free。
ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);
这个是nginx中关于分配共享内存最底层的接口了,它实际上就是直接调用mmap进行共享内存的分配的。对于需要多次分配和释放共享内存的场景来说,直接用这个接口实际是无法忍受效率上的问题,或者有人想到可以直接分配一块大内存自己来进行分配释放的管理,但其实你不用自己做,nginx已经做好这部分的工作了,相关的接口是:
ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
通过这个接口我们可以分配一大块内存,再借助ngx_slab_pool_t这个结构体来管理共享内存。
那nginx又是如何来组织共享内存的呢?
在ngx_cycle_s结构里有一个成员,即ngx_cycle_s->shared_memory,它的类型是ngx_list_t,用来登记所有分配的共享内存,它装的节点类型是ngx_shm_zone_t,一个节点对应一块分配的共享内存,以下是它的源码:
12345678910 | struct ngx_shm_zone_s {//指向自定义数据结构,一般用来初始化时使用,可能指向本地地址void *data;//真正的共享内存ngx_shm_t shm;//初始化函数ngx_shm_zone_init_pt init;//标记void *tag;}; |
1. 两个相同名字的共享内存大小要一样。
2. 两个相同名字的共享内存tag要一样。
3. 如果当前共享内存已经存在,则不需要再次添加。会返回同一个共享内存
4. 如果此共享内存不存在,则添加一个新的ngx_shm_zone_t
添加完后会返回ngx_shm_zone_t,我们需要设置init函数和data数据
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 64 65 66 67 | ngx_shm_zone_t * ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag) { ngx_uint_t i; ngx_shm_zone_t *shm_zone; ngx_list_part_t *part; part = &cf->cycle->shared_memory.part; shm_zone = part->elts; //先查找所有已经存在的共享内存,看看要创建的共享内存是否存在于这里面,如果存在的话就直接返回,否则 //创建一个新的共享内存结构体再返回 for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; i = 0; } if (name->len != shm_zone[i].shm.name.len) { continue; } if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len) != 0) { continue; } if (size && size != shm_zone[i].shm.size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the size %uz of shared memory zone \"%V\" " "conflicts with already declared size %uz", size, &shm_zone[i].shm.name, shm_zone[i].shm.size); return NULL; } if (tag != shm_zone[i].tag) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the shared memory zone \"%V\" is " "already declared for a different use", &shm_zone[i].shm.name); return NULL; } //此共享内存已经存在,直接返回 return &shm_zone[i]; } //插入一个新的共享内存结构体结点 shm_zone = ngx_list_push(&cf->cycle->shared_memory); if (shm_zone == NULL) { return NULL; } shm_zone->data = NULL; shm_zone->shm.log = cf->cycle->log; shm_zone->shm.size = size; shm_zone->shm.name = *name; shm_zone->shm.exists = 0; shm_zone->init = NULL; shm_zone->tag = tag; return shm_zone; } |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 | ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle){。。。 /* create shared memory */ part = &cycle->shared_memory.part; shm_zone = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; i = 0; } if (shm_zone[i].shm.size == 0) { ngx_log_error(NGX_LOG_EMERG, log, 0, "zero size shared memory zone \"%V\"", &shm_zone[i].shm.name); goto failed; }//注意这里,没有设置init函数的共享内存是被视为不使用的 if (shm_zone[i].init == NULL) { /* unused shared zone */ continue; } shm_zone[i].shm.log = cycle->log;//这里主要是考虑reload操作 opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (n = 0; /* void */ ; n++) { if (n >= opart->nelts) { if (opart->next == NULL) { break; } opart = opart->next; oshm_zone = opart->elts; n = 0; } if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { continue; } if (ngx_strncmp(shm_zone[i].shm.name.data, oshm_zone[n].shm.name.data, shm_zone[i].shm.name.len) != 0) { continue; }//如果新的共享内存和旧的共享内存大小一样,就无需再次分配了,直接指过去即可 if (shm_zone[i].shm.size == oshm_zone[n].shm.size) { shm_zone[i].shm.addr = oshm_zone[n].shm.addr;//这里还需要重新初始化一下,因为可能会有对本地内存的操作 if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data) != NGX_OK) { goto failed; } goto shm_zone_found; }//如果老的共享内存和新的要分配的共享内存大小不一致,那就只能释放掉了 ngx_shm_free(&oshm_zone[n].shm); break; }//真正分配共享内存的调用 if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) { goto failed; }//初始化共享内存,为用slab来管理内存池做准备 if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) { goto failed; }//调用设置的init函数 if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) { goto failed; } shm_zone_found: continue; }。。。} |
ngx_init_zone_pool主要的目的就是让我们可以通过slab来分配、释放内存(具体的用法这里暂不提及,以后有空可以专门写一篇文章来说)。下面我们来看看ngx_init_zone_pool的实现吧:
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 | static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn) { u_char *file; ngx_slab_pool_t *sp; //通过slab来管理内存 sp = (ngx_slab_pool_t *) zn->shm.addr; if (zn->shm.exists) { if (sp == sp->addr) { return NGX_OK; } ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "shared zone \"%V\" has no equal addresses: %p vs %p", &zn->shm.name, sp->addr, sp); return NGX_ERROR; } //初始化slab分配器 sp->end = zn->shm.addr + zn->shm.size; sp->min_shift = 3; sp->addr = zn->shm.addr; #if (NGX_HAVE_ATOMIC_OPS) file = NULL; #else file = ngx_pnalloc(cycle->pool, cycle->lock_file.len + zn->shm.name.len); if (file == NULL) { return NGX_ERROR; } (void) ngx_sprintf(file, "%V%V%Z", &cycle->lock_file, &zn->shm.name); #endif //创建共享内存的锁 if (ngx_shmtx_create(&sp->mutex, (void *) &sp->lock, file) != NGX_OK) { return NGX_ERROR; } ngx_slab_init(sp); return NGX_OK; } |
ngx_slab_free。
相关文章推荐
- 数据结构实践——稀疏矩阵的三元组表示
- 数据结构之队列定义及基本操作实现
- Android OpenCV中的几种基本数据结构
- 大话数据结构——第一、二章
- 一些数据结构算法
- 数据结构-链式线性表基本操作实现
- 【C语言】数据结构――动态顺序表
- C语言数据结构之图的遍历
- C语言数据结构之二叉树的操作
- C语言数据结构之栈与队列的应用(3)
- C语言数据结构之栈与队列的应用(2)
- C语言数据结构之栈与队列的应用(1)进制转换
- C语言数据结构之线性表的基本操作
- Java数据结构面试题
- Miscalculation(模拟题)
- Python解析json数据结构范例
- 数据结构实践项目——树和二叉树(2)
- 数据结构实践——用二叉树求解代数表达式
- 【数据结构与算法分析】1.3 用printOut函数输出任意实数
- 【数组项目3-稀疏矩阵的三元组表示的实现及应用——第9周】