参考ngin官方模块对于共享内存的使用,可以在配置文件中对共享内存进行配置
{
ngx_string("srs_request_node_zone"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_http_srs_request_node_zone,
0,
0,
NULL
},如上代码,配置参数为共享内存信息配置
srs_request_node_zone zone=test:400M;这个配置说明配置一个名为test的400M大小的共享内存,在初始化模块的时候,会调用ngx_http_srs_request_node_zone进行配置(主要看注释的代码):
static char *
ngx_http_srs_request_node_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
u_char *p;
ssize_t size;
ngx_str_t *value, name, s;
ngx_shm_zone_t *shm_zone;
ngx_http_srs_hook_ctx_t *ctx;
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_srs_hook_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
value = cf->args->elts; //获取配置的参数,有两个一个是配置名srs_request_node_zone , 一个是配置的参数zone=test:400M
size = 0;
name.len = 0;
if (ngx_strncmp(value[1].data, "zone=", 5) == 0) //对配置解析获取共享内存名和大小
{
name.data = value[1].data + 5;
p = (u_char *) ngx_strchr(name.data, ':');
if (p == NULL)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid zone size \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
name.len = p - name.data;
s.data = p + 1;
s.len = value[1].data + value[1].len - s.data;
size = ngx_parse_size(&s);
if (size == NGX_ERROR)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid zone size \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
if (size < (ssize_t) (8 * ngx_pagesize))
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"zone \"%V\" is too small", &value[1]);
return NGX_CONF_ERROR;
}
}
else
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid zone size \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
if (name.len == 0)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"\"%V\" must have \"zone\" parameter", &cmd->name);
return NGX_CONF_ERROR;
}
shm_zone = ngx_shared_memory_add(cf, &name, size, &ngx_http_srs_hook_module); //将获取到的name和size作为参数给ngx_shared_memory_add,得到shm_zone,<span> </span> //这个就是共享内存的指针
if (shm_zone == NULL)
{
return NGX_CONF_ERROR;
}
if (shm_zone->data)
{
//ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"%V \"%V\" is already bound to key \"%V\"",&cmd->name, &name, &ctx->key.value);
return NGX_CONF_ERROR;
}
shm_zone->init = ngx_http_srs_request_node_init_zone; //设置共享内存的初始化函数
shm_zone->data = ctx; //设置共享内存的外带数据
return NGX_CONF_OK;
}以上就是进行共享内存创建的方法,现在具体说下共享内存创建的原理:
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; //可以看出nginx的共享内存都是存放在cf->cycle->shared_memory.part这个结构中的,不需要深入看,使用这个知道这层就够了 shm_zone = part->elts; //获取到这个共享内存存放链表的头指针
for (i = 0; /* void */ ; i++) { //从这个for循环开始就是获取所指定的共享内存
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 (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;
}
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;
}
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;
}
从以上代码可以看出,nginx会先查找指定的共享内存是否已经存在,如果存在就直接从链表中找到并返回,如果没有找到的话就会创建一个共享内存节点放到链表中并且更具tag等参数初始化,随后将找到的或新加的共享内存节点返回。
至此共享内存就创建完毕了,可能大家会怀疑为什么没有看到真正的创建过程,其实这些nginx都给我们封装在内部了, 在nginx进程进行初始化的时候,就为我们之前加入的这个共享内存链表进行内存分配了
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;
}
// 跳过未使用的共享内存
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;
}
// 这里调用我们自己的初始化函数,注意第二个参数是NULL的
if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
goto failed;
}
shm_zone_found:
continue;
}
........ngx_init_zone_pool这个函数初始化了slab结构用来方便操作所分配的共享内存
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;
sp = (ngx_slab_pool_t *) zn->shm.addr; //可以看出ngx_shm_zone_t的shm.addr成员就是ngx_slab_pool_t
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;
}
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, &sp->lock, file) != NGX_OK) { //初始化slab中的锁,用于多进程间的同步
return NGX_ERROR;
}
ngx_slab_init(sp);
return NGX_OK;
}接着来看下对于共享内存有哪些使用的操作
每一块共享内存在nginx内部都是由slab进行管理的,诸如分配删除等内存操作,具体的slab的概念可以google,网上已经很多了
void *
ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size) void *
ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)void
gx_slab_free(ngx_slab_pool_t *pool, void *p)void
ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)最主要就是这两个接口,分配和释放,却别只在于内部有无锁
使用举个列子:
ngx_slab_pool_t *shpool;
shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
ngx_shmtx_lock(&shpool->mutex);
segmentinfo_t* si_t = ngx_slab_calloc_locked(shpool,sizeof(segmentinfo_t));
if(!si_t)
{
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
"srs_hook: craete segmentinfo struct take error\n");
ngx_shmtx_unlock(&shpool->mutex);
return NGX_ERROR;
}<pre name="code" class="html">ngx_shmtx_unlock(&shpool->mutex);ngx_shmtx_unlock(&shpool->mutex);ngx_slab_free(shpool,si_t );ngx_shmtx_lock(&shpool->mutex);
本文详细介绍了如何在nginx配置文件中设置共享内存,并解释了在nginx进程初始化时如何为共享内存分配内存。此外,文章还探讨了共享内存的slab管理机制,包括分配和删除操作。
2103

被折叠的 条评论
为什么被折叠?



