内容简介:Swoole 源码分析——内存模块之共享内存
前言
我们知道,由于 PHP 没有多线程模型,所以 swoole 更多的使用多进程模型,因此代码相对来说更加简洁,减少了各种线程锁的阻塞与同步,但是也带来了新的问题:数据同步。相比多线程之前可以直接共享进程的内存,进程之间数据的相互同步依赖于共享内存。本文将会讲解 swoole 中共享内存的源码。
前置知识:
mmap函数的使用: APUE 学习笔记——高级 IO- 共享内存: APUE 学习笔记——进程间通信
共享内存数据结构
typedef struct _swShareMemory_mmap
{
size_t size;
char mapfile[SW_SHM_MMAP_FILE_LEN];
int tmpfd;
int key;
int shmid;
void *mem;
} swShareMemory;
-
注意
mem是一个void类型的指针,用于存放共享内存的首地址。这个成员变量相当于面向对象中的this指针,通过它就可以访问到swShareMemory的各个成员。 size代表共享内存的大小(不包括swShareMemory结构体大小),mapfile[]代表共享内存使用的内存映射文件的文件名,tmpfd为内存映射文件的描述符。key代表使用System V的shm系列函数创建的共享内存的key值,shmid为shm系列函数创建的共享内存的id(类似于fd),这两个由于不是POSIX标准定义的api,用途有限。
共享内存的申请与创建
swoole 在申请共享内存时常常调用的函数是 sw_shm_malloc,这个函数可以为进程匿名申请一大块连续的共享内存:
void* sw_shm_malloc(size_t size)
{
swShareMemory object;
void *mem;
size += sizeof(swShareMemory);
mem = swShareMemory_mmap_create(&object, size, NULL);
if (mem == NULL)
{
return NULL;
}
else
{
memcpy(mem, &object, sizeof(swShareMemory));
return mem + sizeof(swShareMemory);
}
}
- 从
sw_shm_malloc函数可以看出,虽然我们申请的是size,但是实际申请的内存是要略大的,因为还要加上swShareMemory这个结构体。当函数返回时,也不会直接返回申请的内存首地址,而是复制了object各个成员变量的值后,在申请的首地址上加上swShareMemory的大小。
void *swShareMemory_mmap_create(swShareMemory *object, size_t size, char *mapfile)
{
void *mem;
int tmpfd = -1;
int flag = MAP_SHARED;
bzero(object, sizeof(swShareMemory));
#ifdef MAP_ANONYMOUS
flag |= MAP_ANONYMOUS;
#else
if (mapfile == NULL)
{
mapfile = "/dev/zero";
}
if ((tmpfd = open(mapfile, O_RDWR)) < 0)
{
return NULL;
}
strncpy(object->mapfile, mapfile, SW_SHM_MMAP_FILE_LEN);
object->tmpfd = tmpfd;
#endif
#if defined(SW_USE_HUGEPAGE) && defined(MAP_HUGETLB)
if (size > 2 * 1024 * 1024)
{
flag |= MAP_HUGETLB;
}
#endif
mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flag, tmpfd, 0);
#ifdef MAP_FAILED
if (mem == MAP_FAILED)
#else
if (!mem)
#endif
{
swWarn("mmap(%ld) failed. Error: %s[%d]", size, strerror(errno), errno);
return NULL;
}
else
{
object->size = size;
object->mem = mem;
return mem;
}
}
-
由于
swoole的各个进程都是由master进程所建立,也就是各个进程之间存在亲戚关系, 因此swShareMemory_mmap_create函数直接以匿名映射、(/dev/zero设备) 的方式利用mmap建立共享内存,并没有open具体的共享内存文件,或者调用shm_open打开POSIX IPC名字。 - 值得注意的是
MAP_HUGETLB,这个是linux内核2.6.32引入的一个flags,用于使用大页面分配共享内存。大页是相对传统4K小页而言的,一般来说常见的体系架构都会提供2种大页大小,比如常见的2M大页和1G大页。使用大页可以减少页表项数量,从而减少TLB Miss的概率,提升系统访存性能。当然有利必有弊,使用大页降低了内存管理的粒度和灵活性,如果程序并不是对内存的使用量特别大,使用大页还可能造成内存的浪费。
共享内存的 calloc
calloc 与 malloc 大同小异,无非多了一个 num 参数
void* sw_shm_calloc(size_t num, size_t _size)
{
swShareMemory object;
void *mem;
void *ret_mem;
int size = sizeof(swShareMemory) + (num * _size);
mem = swShareMemory_mmap_create(&object, size, NULL);
if (mem == NULL)
{
return NULL;
}
else
{
memcpy(mem, &object, sizeof(swShareMemory));
ret_mem = mem + sizeof(swShareMemory);
bzero(ret_mem, size - sizeof(swShareMemory));
return ret_mem;
}
}
共享内存的 realloc
realloc 函数用于修改已申请的内存大小,逻辑非常简单,先申请新的内存,进行复制后,再释放旧的内存:
void* sw_shm_realloc(void *ptr, size_t new_size)
{
swShareMemory *object = ptr - sizeof(swShareMemory);
void *new_ptr;
new_ptr = sw_shm_malloc(new_size);
if (new_ptr == NULL)
{
return NULL;
}
else
{
memcpy(new_ptr, ptr, object->size);
sw_shm_free(ptr);
return new_ptr;
}
}
修改共享内存的权限
在内存映射完成后,由标记读、写、执行权限的 PROT_READ、PROT_WRITE 和 PROT_EXEC 等权限仍可以被 mprotect 系统调用所修改。
int sw_shm_protect(void *addr, int flags)
{
swShareMemory *object = (swShareMemory *) (addr - sizeof(swShareMemory));
return mprotect(object, object->size, flags);
}
共享内存的释放
void sw_shm_free(void *ptr)
{
swShareMemory *object = ptr - sizeof(swShareMemory);
swShareMemory_mmap_free(object);
}
int swShareMemory_mmap_free(swShareMemory *object)
{
return munmap(object->mem, object->size);
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Swoole 源码分析——内存模块之内存池
- Swoole 源码分析——内存模块之共享内存表
- Golang 内存管理源码剖析
- Go内存管理源码浅析
- 从源码解密Spark内存管理
- Netty源码分析--内存模型(上)(十一)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Design Handbook
Baeck, Philippe de 编 / 2009-12 / $ 22.54
This non-technical book brings together contemporary web design's latest and most original creative examples in the areas of services, media, blogs, contacts, links and jobs. It also traces the latest......一起来看看 《Web Design Handbook》 这本书的介绍吧!