当前位置: 首页 > 后端技术 > PHP

Swoole源码分析-内存模块共享内存

时间:2023-03-30 03:20:33 PHP

前言我们知道,由于PHP没有多线程模型,swoole更多的是使用多进程模型,所以代码相对更加简洁,减少了各种线程的阻塞锁和同步,但是也带来了一个新的问题:数据同步。与多线程之前进程内存可以直接共享相比,进程间数据的相互同步依赖于共享内存。本文将讲解swoole中共享内存的源码。前置知识:mmap函数的使用:APUE学习笔记-IO共享内存进阶:APUE学习笔记-进程间通信共享内存数据结构typedefstruct_swShareMemory_mmap{size_tsize;字符映射文件[SW_SHM_MMAP_FILE_LEN];inttmpfd;内部密钥;内部shmid;void*mem;}swShareMemory;注意mem是一个void类型的指针,用来存放共享内存的首地址。这个成员变量相当于面向对象中的this指针,通过它可以访问swShareMemory的各个成员。size表示共享内存的大小(不包括swShareMemory结构的大小),mapfile[]表示共享内存使用的内存映射文件的文件名,tmpfd是内存映射文件的描述符。key表示使用SystemV的shm系列函数创建的共享内存的键值,shmid是shm系列函数创建的共享内存的id(类似于fd)。这两个用途有限,因为它们不是POSIX标准定义的API。共享内存的申请与创建swoole在申请共享内存时经常调用的函数是sw_shm_malloc,它可以为进程匿名申请一块大的连续共享内存:void*sw_shm_malloc(size_tsize){swShareMemoryobject;无效*内存;大小+=sizeof(swShareMemory);mem=swShareMemory_mmap_create(&object,size,NULL);如果(内存==NULL){返回NULL;}else{memcpy(mem,&object,sizeof(swShareMemory));返回内存+sizeof(swShareMemory);}}从sw_shm_malloc函数可以看出,虽然我们申请了size,但是由于还加入了swShareMemory结构,所以实际申请的内存略大。函数返回时,不会直接返回申请内存的首地址,而是复制object的各个成员变量的值,并将swShareMemory的大小加到申请的首地址上。void*swShareMemory_mmap_create(swShareMemory*object,size_tsize,char*mapfile){void*mem;inttmpfd=-1;intflag=MAP_SHARED;bzero(object,sizeof(swShareMemory));#ifdefMAP_ANONYMOUS标志|=MAP_ANONYMOUS;#elseif(mapfile==NULL){mapfile="/dev/zero";}if((tmpfd=open(mapfile,O_RDWR))<0){返回NULL;}strncpy(object->mapfile,mapfile,SW_SHM_MMAP_FILE_LEN);object->tmpfd=tmpfd;#endif#ifdefined(SW_USE_HUGEPAGE)&&defined(MAP_HUGETLB)if(size>2*1024*1024){flag|=MAP_HUGETLB;}#endifmem=mmap(NULL,size,PROT_READ|PROT_WRITE,flag,tmpfd,0);#ifdefMAP_FAILEDif(mem==MAP_FAILED)#elseif(!mem)#endif{swWarn("mmap(%ld)失败。错误:%s[%d]",大小,strerror(errno),errno);返回空值;}else{object->size=size;对象->内存=内存;返回内存;}}由于swoole的各个进程都是由master进程建立的,即各个进程之间是有关系的,所以swShareMemory_mmap_create函数直接使用mmap以匿名映射(/dev/zerodevice)的形式创建共享内存,有没有具体打开Sharedmemoryfiles,还是调用shm_open打开POSIXIPC值得注意的名字是MAP_HUGETLB,这是linux内核2.6.32引入的flag,用于使用largepages分配sharedmemory。大页面是相对于传统的4K小页面而言的。一般来说,常见的架构提供两种巨页大小,比如常见的2M巨页和1G巨页。使用大页可以减少页表项的数量,从而降低TLBMiss的概率,提高系统内存访问性能。当然,有优点也有缺点。大页面的使用降低了内存管理的粒度和灵活性。如果程序不使用大量内存,使用大页也可能造成内存浪费。共享内存的calloccalloc与malloc类似,只是多了一个num参数void*sw_shm_calloc(size_tnum,size_t_size){swShareMemoryobject;无效*内存;void*ret_mem;intsize=sizeof(swShareMemory)+(num*_size);mem=swShareMemory_mmap_create(&object,size,NULL);如果(内存==NULL){返回NULL;}else{memcpy(mem,&object,sizeof(swShareMemory));ret_mem=mem+sizeof(swShareMemory);bzero(ret_mem,size-sizeof(swShareMemory));返回ret_mem;}}共享内存的reallocrealloc函数用于修改申请的内存大小。逻辑很简单。先申请新内存,复制,然后释放旧内存:void*new_ptr;new_ptr=sw_shm_malloc(new_size);如果(new_ptr==NULL){返回NULL;}else{memcpy(new_ptr,ptr,object->size);sw_shm_free(ptr);返回新指针;}}内存映射完成后,修改共享内存的权限由PROT_READ、PROT_WRITE和PROT_READ、PROT_WRITE和PRO标记T_EXEC等权限仍然可以通过mprotect系统调用进行修改returnmprotect(object,object->size,flags);}释放共享内存voidsw_shm_free(void*ptr){swShareMemory*object=ptr-sizeof(swShareMemory);swShareMemory_mmap_free(object);}intswShareMemory_mmap_free(swShareMemory*object){returnmunmap(object->mem,object->size);}

最新推荐
猜你喜欢