精华内容
下载资源
问答
  • 【Linux】Linux的共享内存

    万次阅读 多人点赞 2018-08-10 19:17:45
    实现进程间通信最简单也是最直接的方法就是共享内存——为参与通信的多个进程在内存中开辟一个共享区。由于进程可以直接对共享内存进行读写操作,因此这种通信方式效率特别高,但其弱点是,它没有互斥机制,需要信号...

    实现进程间通信最简单也是最直接的方法就是共享内存——为参与通信的多个进程在内存中开辟一个共享区。由于进程可以直接对共享内存进行读写操作,因此这种通信方式效率特别高,但其弱点是,它没有互斥机制,需要信号量之类的手段来配合。

     

    共享内存原理与shm系统

    共享内存,顾名思义,就是两个或多个进程都可以访问的同一块内存空间,一个进程对这块空间内容的修改可为其他参与通信的进程所看到的。

    显然,为了达到这个目的,就需要做两件事:一件是在内存划出一块区域来作为共享区;另一件是把这个区域映射到参与通信的各个进程空间。

    通常在内存划出一个区域的方法是,在内存中打开一个文件,若通过系统调用mmap()把这个文件所占用的内存空间映射到参与通信的各个进程地址空间,则这些进程就都可以看到这个共享区域,进而实现进程间的通信。

    为了方便,再把mmap()的原理简述如下:

    mmap()原型如下:

    void * mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset);

    其中,参数fd用来指定被映射的文件;offset指定映射的起始位置偏移量(通常为0);len指定文件被映射部分的长度;start用来指定映射到虚地址空间的起始位置(通常为NULL,即由系统确定)。

    mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。

    mmap()映射过程示意图如下所示:

    那么mmap是怎么形成这个文件映射过程呢?

    mmap本身其实是一个很简单的操作,在进程页表中添加一个页表项,该页表项是物理内存的地址。调用mmap的时候,内核会在该进程的地址空间的映射区域查找一块满足需求的空间用于映射该文件,然后生成该虚拟地址的页表项,改页表项此时的有效位(标志是否已经在物理内存中)为0,页表项的内容是文件的磁盘地址,此时mmap的任务已经完成。 

    简而言之,就是在进程对应的虚存段添加一个段,也就是创建一个新的vm_area_struct结构,并将其与文件的物理磁盘地址相连。在创建虚拟区间并完成地址映射,但是并没有将任何文件数据的拷贝至主存。真正的文件读取是当进程发起读或写操作时。进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,引发缺页异常,内核进行请页。

    IPC的共享内存通信方式与上面的mmap()方式极为相似,但因为建立一个文件的目的仅是为了通信,于是这种文件没有永久保存的意义,因此IPC并没有使用正规的文件系统,而是在系统初始化时在磁盘交换区建立了一个专门用来实现共享内存的特殊临时文件系统shm,当系统断电后,其中的文件会全部自行销毁。

    文章参考:mmap内存映射认真分析mmap:是什么 为什么 怎么用

     

    Linux共享内存结构

    Linux的一个共享内存区由多个共享段组成。用来描述共享内存段的内核数据结构shmid_kernel如下:

    struct shmid_kernel /* private to the kernel */
    {	
    	struct kern_ipc_perm	shm_perm;        //描述进程间通信许可的结构
    	struct file *		shm_file;            //指向共享内存文件的指针
    	unsigned long		shm_nattch;            //挂接到本段共享内存的进程数
    	unsigned long		shm_segsz;            //段大小
    	time_t			shm_atim;            //最后挂接时间
    	time_t			shm_dtim;            //最后解除挂接时间
    	time_t			shm_ctim;            //最后变化时间
    	pid_t			shm_cprid;            //创建进程的PID
    	pid_t			shm_lprid;            //最后使用进程的PID
    	struct user_struct	*mlock_user;
    };

    shmid_kernel中最重要的域是指针shm_file,它指向临时文件file对象。当进程需要使用这个文件进行通信时,由内核负责将其映射到用户地址空间。

    为了便于管理,内核把共享内存区的所有描述结构shmid_kernel都存放在结构ipc_id_ary中的一个数组中。结构ipc_id_ary的定义如下:

    struct ipc_id_ary
    {
            int size;
            struct kern_ipc_perm *p[0];            //存放段描述结构的数组
    };

    同样,为了描述一个共享内存区的概貌,内核使用了数据结构ipc_ids。该结构的定义如下:

    struct ipc_ids {
    	int in_use;
    	unsigned short seq;
    	unsigned short seq_max;
    	struct rw_semaphore rw_mutex;
    	struct idr ipcs_idr;
            struct ipc_id_ary *entries;        //指向struct ipc_id_ary的指针
    };

    由多个共享段组成的共享区的结构如下所示:

     

    共享内存的使用

    头文件:

    #include <sys/shm.h>

    共享内存的打开或创建

    进程可以通过调用函数shmget()来打开或创建一个共享内存区。函数shmget()内部由系统调用sys_shmget来实现。函数shmget()的原型如下:

    int shmget(key_t key, size_t size, int flag);

    其中,参数key为用户给定的键值。

    所谓的键值,是在IPC的通信模式下每个IPC对象的名字。进程通过键值识别所有的对象。如果不使用键,进程将无法获取IPC对象,因此IPC对象并不存在于进程本身所使用的的内存中。

    因此任何进程都无法为一块共享内存定义一个键值。因此,在调用函数shmget()时,需要key设为IPC_PRIVATE,这样,操作系统将忽略键,建立一个新的共享内存,指定一个键值并返回这块共享内存的IPC标识符ID,然后再设法将这个新的共享内存的标识符ID告诉其他需要使用这个共享内存区的进程。

    函数中的参数size为所申请的共享存储段的长度(以页为单位)。

    函数中的参数flag为标志,常用的有效标志有IPC_CREAT和IPC_EXCL,它们的功能与文件打开函数open()的O_CREAT和O_EXCL相当。如果用户希望所创建的共享内存区可读,则需要使用标志S_IRUSR;若可读,则需要使用标志S_IWUSR。

    函数shmget()调用成功后,返回共享内存区的ID,否则返回-1。

    Linux用shmid_ds数据结构表示每个新建的共享内存。当shmget()创建一块新的共享内存后,返回一个可以引用该共享内存的shmid_ds数据结构的标识符。定义在include/linux/shm.h文件中的shmid_ds如下:

    struct shmid_ds {
    	struct ipc_perm		shm_perm;	/* operation perms */
    	int			shm_segsz;	/* size of segment (bytes) */
    	__kernel_time_t		shm_atime;	/* last attach time */
    	__kernel_time_t		shm_dtime;	/* last detach time */
    	__kernel_time_t		shm_ctime;	/* last change time */
    	__kernel_ipc_pid_t	shm_cpid;	/* pid of creator */
    	__kernel_ipc_pid_t	shm_lpid;	/* pid of last operator */
    	unsigned short		shm_nattch;	/* no. of current attaches */
    	unsigned short 		shm_unused;	/* compatibility */
    	void 			*shm_unused2;	/* ditto - used by DIPC */
    	void			*shm_unused3;	/* unused */
    };

    例如:调用函数shmget()为当前进程创建一个共享内存区。

    代码如下:

    int main(void)
    {
            int shmid;
            if((shmid = shmget(IPC_PRIVATE, 10, IPC_CREAT)) < 0)
            {
                    perror("shmget error!");
                    exit(1);
            }else
                    printf("shmget success!");
    
            return 0;
    }

    共享内存与进程的连接

    如果一个进程已创建或打开一个共享内存,则在需要使用它时,要调用函数shmat()把该共享内存连接到进程上,即要把待使用的共享内存映射到进程空间。函数shmat()通过系统调用sys_shmat()实现。函数shmat()的原型如下:

    void * shmat(int shmid, char __user * shmaddr, int shmflg);

    其中,参数shmid为共享内存的标识;参数shmaddr为映射地址,如果该值为0,则由内核决定;参数shmflg为共享内存的标志,如果shmflg的值为SHM_RDONLY,则进程以只读的方式访问共享内存,否则以读写方式访问共享内存。

    若函数调用成功,则返回共享存储段地址;若出错,则返回-1。

    断开共享内存与进程的连接

    调用函数shmdt()可以断开共享内存与进程的连接,其原型如下:

    int shmdt(coid * addr);

    其中,参数addr为共享存储段的地址,即调用shmat时的返回值。shmdt将使相关shmid_ds结构中的shm_nattch计数器值减1。

    共享内存的控制

    调用函数shmctl()可以对共享内存进行一些控制,其原型如下:

    int shmctl(int shmid, int cmd, struct shmid_ds * buf);

    其中,参数shmid为共享存储段的ID;参数cmd为控制命令,常用的值有IPC_STAT(赋值)、IPC_SET(赋值)、IPC_RMID(删除)、SHM_LOCK(上锁)、SHM_UNLOCK(解锁)等等;参数buf为struct shmid_ds类型指针,由buf返回的数值与命令参数cmd表示的操作相关。

    共享内存不会随着程序的结束而自动消除,要么调用shmctl()删除,要么手动使用命令ipcrm -m shmid去删除,否则一直保留在系统中,直至系统掉电。

    例子:调用函数shmget()为当前进程创建一个共享内存区并使用它。

    代码如下:

    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <stdio.h>
    #include <sys/stat.h>
    
    int main(void)
    {
    	int shm_id;							//定义共享内存键
    	char* shared_memory;				//定义共享内存指针
    	struct shmid_ds shmbuffer;			//定义共享内存缓冲
    	int shm_size;						//定义共享内存大小
    
    	shm_id = shmget(IPC_PRIVATE, 0x6400, IPC_CREAT | IPC_EXCL | S_IRUSE | S_IWUSE);		//创建一个共享内存区
    	shared_memory = (char*)shmat(shm_id, 0, 0);					//绑定到共享内存
    	printf("shared memory attached at address %p\n", shared_memory);
    
    	shmctl(shm_id, IPC_STAT, &shmbuffer);				//读共享内存结构struct shmid_ds
    	shm_size = shmbuffer.shm_segsz;						//自结构struct shmid_ds获取内存大小
    	printf("segment size:%d\n", shm_size);
    
    	sprintf(shared_memory, "Hello,world.");				//向共享内存中写入一个字符串
    	shmdt(shared_memory);							//脱离该共享内存
    
    	shared_memory = (char*)shmat(shm_id, (void *)0x500000, 0);			//重新绑定共享内存
    	printf("shared memory reattched at address %p\n", shared_memory);
    	printf("%s\n", shared_memory);
    	shmdt(shared_memory);						//脱离该共享内存
    	shmctl(shm_id, IPC_RMID, 0);				//释放共享内存
    
    	return 0;
    }

    共享内存的互斥

    从上面的叙述中可以看到,共享内存是一种低级的通信机制,它没有提供进程间同步和互斥的功能。所以,共享内存通常是要与信号量结合使用。

     

    展开全文
  • 进程间通信之共享内存 共享内存就是不同进程之间共享的一块内存区域。一般情况下,每个进程都有自己独立的内存空间,一个进程不能直接访问其他进程的内存区域,这样就使得进程与进程之间不能交流,而共享内存的...

    进程间通信之共享内存

             共享内存就是不同进程之间共享的一块内存区域。一般情况下,每个进程都有自己独立的内存空间,一个进程不能直接访问其他进程的内存区域,这样就使得进程与进程之间不能交流,而共享内存的出现,则使进程之间的相互访问变成了现实。

             共享内存是通过多个进程之间对内存段进行映射的方法来实现内存共享的,这是进程间通信的最快的一种方式,因为此方式没有中间过程,直接将某段内存进行映射,多个进程间的共享内存是同一块物理区间,仅仅是地址不同而已,即同一物理块内存被映射到多个进程各自的进程地址空间中,此时,进程A可以即时看到进程B对共享内存中数据的更新,从而实现进程间通信。

             共享内存本身不带有任何互斥与同步机制,但当多个进程对同一内存进行读写操作时会破坏该内存的内容。所以在实际应用中,同步与互斥需要用户自己来完成。

    共享内存操作函数

    1.int shmget(key_t key,size_t size,int shmflg);

    功能:用来创建共享内存

    参数:key:共享内存段的名字,可直接指定,也可通过ftok()函数产生;size:共享内存的大小,可指定,也可通过调用getpagesize()函数来使用;shmflg:共享内存标记,常取值为IPC_CREAT或IPC_EXCL,单独使用IPC_CREAT时,表示如果共享内存不存在,则创建,如果存在,则打开并返回。但是IPC_EXCL单独使用是没有意义的。通常IPC_CREAT和IPC_EXCL一起使用,表示如果共享内存不存在,则创建,如果存在,则出错,返回。

    返回值:若成功,返回共享内存段的标识码,失败,返回-1。

    2.void* shmat(int shmid,const void* shmaddr,int shmflg);

    功能:用来将内存段映射到进程地址空间

    参数:shmid:共享内存的标识码,shmget()函数的返回值;shmaddr:指定的连接的地址,通常取NULL,表示系统内核会自动选择一个地址;shmflg:共享内存标记,可能取值为SHM_RND和SHM_RDONLY,表示只读内存

    返回值:成功,返回一个指针,指向共享内存的第一个字节;失败,返回-1。

    3.int shmdt(const void* shmaddr);

    功能:将共享内存段与当前进程脱离

    参数:shmaddr:指针,shmat()函数的返回值

    返回值:成功,返回0;失败,返回-1。

    4.int shmctl(int shmid,int cmd,struct shmid_ds* buffer);

    功能:用于控制共享内存

    参数:shmid:共享内存的标识码,shmget()函数的返回值;cmd:有3个可取值,一般使用IPC_RMID;buffer:结构体指针,表示向共享内存发送命令的参数。

    cmd参数的可取值:

    IPC_STAT                           把shmid_ds结构中的数据设置为共享内存的当前关联值

    IPC_SET                             进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds结构中给出的值

    IPC_RMID                         删除共享内存段

    共享内存的效率

             采用共享内存进行进程间通信的最大的一个好处就是效率高,因为进程可以直接读写内存,只拷贝两次数据,一次是从文件区到共享内存区,一次是从共享内存区到输出文件。实际上,进程之间在使用共享内存进行通信时,并不总是读写少量数据后就解除映射,有新的通信时再重新建立共享内存区域,而是一直保持这个共享区域,知道通信完成为止,这样一来,数据内容就一直保存在共享内存中,并没有被写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率很高。

    共享内存的特点

    共享内存就是允许两个不相关的进程访问同一块内存区域

    共享内存是两个正在运行的进程之间共享和传递数据的最有效的方式

    不同进程之间的共享内存通常安排为同一段物理内存

    共享内存不提供任何互斥与同步机制,一般与信号量一起使用来达到对临界资源进行保护的目标

    接口简单

    案例

    1.创建共享内存

    shmget.c

    #include <stdio.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    int main()
    {  
        //获取内存页大小
        int size = getpagesize();
        printf("pagesize = %d\n",size);
        //获取键值
        key_t key = ftok("/tmp",0x123);
        printf("key = 0x%x\n",key);
        //创建共享内存
        //一般情况下,创建时直接在IPC_CREAT后跟权限
        int shmid = shmget(key,size,IPC_CREAT | 0666);
        if(shmid == -1)
        {
            perror("shmget");
            return -1;
        }
        printf("shmid = %d\n",shmid);
        return 0;
    }

    编译运行之后可通过ipcs –m来查看共享内存的信息

    2.对共享内存的读取操作1

    shmwrite1.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/shm.h>
    int main()
    {
        key_t key=ftok("/tmp",0x66);
        int pagesize = getpagesize();
        int shmid=shmget(key,pagesize,IPC_CREAT | 0666);
        if(shmid == -1)
        {
            perror("shmget");
            return -1;    
        }
        //将共享内存映射到进程的地址空间
        int *pNum=(int*)shmat(shmid,NULL,0);
        *pNum = 666;
        if(pNum==(void*)-1)
        {
            perror("shmat");
            return -1;
        }
        *(pNum+1) = 888;
        return 0;
    }

    shmread1.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/shm.h>
    int main()
    {
        key_t key=ftok("/tmp",0x66);
        int pagesize = getpagesize();
        int shmid=shmget(key,pagesize,IPC_CREAT | 0666);
        if(shmid == -1)
        {
            perror("shmget");
            return -1;    
        }
        //将共享内存映射到进程的地址空间
        int *pNum=(int*)shmat(shmid,NULL,0);
        if(pNum==(void*)-1)
        {
            perror("shmat");
            return -1;
        }
        printf("pNum1 = %d,pNum2 = %d\n",*pNum,*(pNum + 1));
        return 0;
    }

    运行时,先运行shmwrite1,将内容写到共享内存上,之后再运行shmread1读取

    3.对共享内存的读取操作2

    shmwrite2.c

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #define size 4096
    typedef struct _Data
    {
        int flag;
        char szMsg[size];
    }Data;
    
    int main()
    {
        //创建共享内存
        key_t key = ftok("/tmp",0x1234);
        int shmid = shmget(key,sizeof(Data),IPC_CREAT | 0666);
        if(shmid == -1)
        {
            perror("shmget");
            return -1;
        }
        //将共享内存映射到进程的内存空间
        void *shm = shmat(shmid,NULL,0);
        if((void*)(-1) == shm)
        {
            perror("shmat");
            return -1;
        }
        Data* pdata = (Data*)shm;
        pdata -> flag = 0;
        int i = 0;
        while(1)
        {
            if(pdata -> flag == 0)
            {
                sleep(2);
                snprintf(pdata -> szMsg,sizeof(pdata -> szMsg),"Hello World %d",++i);
                printf("Send Msg is [%s]\n",pdata -> szMsg);
                pdata -> flag = 1;
            }
        }
        //将共享内存与进程脱离
        shmdt(shm);
        return 0;
    }
    

     

    shmread2.c

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #define size 4096
    typedef struct _Data
    {
        int flag;
        char szMsg[size];
    }Data;
    
    int main()
    {
        //创建共享内存
        key_t key = ftok("/tmp",0x1234);
        int shmid = shmget(key,sizeof(Data),IPC_CREAT | 0666);
        if(shmid == -1)
        {
            perror("shmget");
            return -1;
        }
        //将共享内存映射到进程的内存空间
        void *shm = shmat(shmid,NULL,0);
        if((void*)(-1) == shm)
        {
            perror("shmat");
            return -1;
        }
        Data* pdata = (Data*)shm;
        while(1)
        {
            if(pdata -> flag == 1)
            {
                printf("Recvive Msg is [%s]\n",pdata -> szMsg);
                pdata -> flag = 0;
            }
        }
        //将共享内存与进程脱离
        shmdt(shm);
        //删除共享内存
        shmctl(shmid,IPC_RMID,0);
        return 0;
    }

     

    运行时需要开启两个终端

    4.用共享内存实现客户端与服务器端的简单通信

    Server_shm.c

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    int main()
    {
        //创建共享内存
        key_t key = ftok("/tmp",0x1234);
        if(key < 0)
        {
            perror("ftok");
            return -1;
        }
        int size = getpagesize();
        int shmid = shmget(key,size,IPC_CREAT | 0666);
        if(shmid < 0)
        {
            perror("shmget");
            return -1;
        }
        //将共享内存映射到进程的地址空间
        char* address = shmat(shmid,NULL,0);
        int i = 0;
        while(i < 26)
        {
            address[i] = 'A' + i;
            i++;
            address[i] = 0;
            sleep(1);
        }
        //解除共享内存的映射
        shmdt(address);
        sleep(3);
        //删除共享内存
        shmctl(shmid,IPC_RMID,NULL);
        return 0;
    }

     

    Client_shm.c

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    int main()
    {
        //创建共享内存
        key_t key = ftok("/tmp",0x1234);
        if(key < 0)
        {
            perror("ftok");
            return -1;
        }
        int size = getpagesize();
        int shmid = shmget(key,size,IPC_CREAT | 0666);
        if(shmid < 0)
        {
            perror("shmget");
            return -1;
        }
        //将共享内存映射到进程的地址空间
        char* address = shmat(shmid,NULL,0);
        int i = 0;
        while(i < 26)
        {
            printf("client:%s\n",address);
            i++;
            sleep(1);
        }
        //解除共享内存的映射
        shmdt(address);
        return 0;
    }

     

    运行时开俩终端,分别执行客户端程序和服务器端程序。客户端中,当i = 26时,自动退出,3秒后,共享内存段销毁。

    删除共享内存

    共享内存删除时有两种方法:系统命令和shmctl()函数

    shmctl()函数在上面的案例中已经使用过了,接下来我们来了解如何用命令删除共享内存。首先,使用命令ipcs –m先查看一下共享内存,之后再使用ipcrm –M命令来删除

    可以看到,权限为666的两个共享内存段是我们进行上面案例演示时创建的。接下来我们删除它们。

    我们看到,刚才的两个权限为666的共享内存段已经被删除。

    展开全文
  • 无论是Linux还是Windows,都会提供一定大小的内存给应用程序来使用,共享内存就像一个设置了权限的文件,允许你像操作文件一样操作共享内存。 比如,PHP多进程之间的通讯,你可以使用临时文件,管道,或者共享内存来...

    Linux下的共享内存有三种方式:sysv,posix,mmap。但是php只提供了操作sysv的函数,所以下面要说的就是sysv的共享内存,Linux系统提供了三个工具来满足IPC通讯:消息队列,共享内存段,信号量。

    ipcs 命令

    root@localhost:/usr/local/bin# ipcs
    
    ------ Message Queues --------
    key        msqid      owner      perms      used-bytes   messages
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status
    
    ------ Semaphore Arrays --------
    key        semid      owner      perms      nsems
    

    PHP提供的扩展,不需要安装,但是需要手动开启。

    shmop 共享内存,只能按字节操作
    sysvsem 信号量
    sysvshm 共享内存,和 shmop 的差别是提供的操作函数不同,支持 key、value操作
    sysvmsg 消息队列
    

    sysvsem,sysvshm,sysvmsg 的函数列表
    在这里插入图片描述
    shmop 的函数列表
    在这里插入图片描述
    看来 sysvshm 扩展和 shmop 扩展功能差不多。

    sysvshm 扩展提供的方法在存储之前对用户的数据进行serialize处理,这里就导致这个存储的数据是无法与其它语言共享的,这一系列方法是php only的方法。

    shmop系列函数,虽然能实现共享内存操作,但实际上底层实现非常简陋。一方面底层根本没有加锁,如果你要在并发环境中使用,需要自行实现锁的操作。另外,底层实际上是一个链表结构,数据较多时,查询性能非常差。

    无论是Linux还是Windows,都会提供一定大小的内存给应用程序来使用,共享内存就像一个设置了权限的文件,允许你像操作文件一样操作共享内存。

    比如,PHP多进程之间的通讯,你可以使用临时文件,管道,或者共享内存来在进程间交换数据;并且,你也可以通过共享内存来实现不同应用程序间的通讯。

    1、查看已设置的共享内存中的内存段列表
    ipcs -m

    ------------ 共享内存段 --------------
    键key       shmid      拥有者owner  	权限perms   字节bytes    nattch     状态status      
    0x00000360 	0          root     	755      	1024    	0 
    

    以上是有可用的片段的情况,是不是和文件的形式很相似。

    字段解释:

    key 	:共享内存的唯一的key值,共享内存通过该key来判断你读取的是哪一块内存。
    shmid	:当使用key来获取内存时,你获得的是这个id的值。它作为你操作内存块的标识,类型为 resource(4) of type (shmop)
    owner	:创建该共享内存块的用户
    perms	:该共享内存的读写权限,8禁止,可以是777,与文件的读写权限一致。
    bytes	:该内存块的大小,字节
    nattch	:连接该内存块的进程数
    status	:当前状态,如:dest,即将删除等。
    

    key是一个16进制值,我们也可以传10进制值

    一般操作:通过key来打开一个内存段,返回shmid,之后通过这个shmid来操作内存段。

    查看系统共享内存大小

    cd /proc/sys/kernel
    cat shmmax
    

    删除共享内存块
    ipcrm -m shmid
    或者
    ipcrm -M key

    shmop 系列函数
    PHP通过shmop函数来操作共享内存,非常之方便。

    shmop_open()
    	它允许您打开一个现有的内存段或创建一个新内存段。此函数非常类似于经典的fopen函数.
    	$shmid = shmop_open(864, 'c', 0755, 1024);
    
    	第一个参数就是上面的key,如果不存在就会创建,十进制的 864 就是16进制的 0x00000360,都可以使用。返回值就是shmid,失败返回FALSE
    	第二个参数是访问模式
    		模式 “a”,它允许您访问只读内存段
    		模式 “w”,它允许您访问可读写的内存段
    		模式 “c”,它创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写
    		模式 “n”,它创建一个新内存段,如果该内存段已存在,则会失败
    	第三个参数为权限
    	第四个参数为大小,字节
    
    shmop_write()
    	写入数据,失败时会返回 FALSE,在成功时会返回写入的字节数。
    	shmop_write($shmid, "Hello World!", 0);
    	第三个参数为offset
    
    shmop_read()
    	读取共享内存数据
    	$str = shmop_read($shmid, 0, 11);// offset, length
    
    shmop_size()
    	获取指定片段的内存大小,字节
    	$size = shmop_size($shmid);
    
    shmop_delete()
    	标记为删除,阻止任何其他进程打开它,并没有实际删除。因为本进程正在打开该片段,需要关闭后才会实际被删除。
    
    shmop_close()
    	关闭内存段。
    

    实例:
    文件1

    $shmid = shmop_open(864, 'c', 0755, 1024);// 0x00000360
    shmop_write($shmid, "Hello World PHP!", 0); // 注意 data是字符串类型,不管你赋值的是不是字符串。
    shmop_close($shmid);
    

    查看

    ipcs -m
    

    文件2

    $shmid = shmop_open(864, 'c', 0755, 1024);// 0x00000360
    var_dump($shmid);// resource(4) of type (shmop)
    $size = shmop_size($shmid);
    echo shmop_read($shmid, 0, $size) . PHP_EOL;
    shmop_close($shmid);
    

    当然,也可以使用其他程序打开,比如java, c++等

    并发的问题
    共享内存的操作并不是原子性的,多个进程同时操作就存在并发的问题,需要通过信号量来加锁。

    在共享数据方面,效率最高的是内存,其次是本地问文件,最慢的是网络IO(memcache, redis,mysql等)。

    展开全文
  • 本节描述如果数据库实例当前启用了自动内存管理或手动共享内存管理,如何更改为自动共享内存管理。 如果当前启用自动内存管理,则更改为自动共享内存管理: 如果当前启用了自动内存管理,但您希望对系统全局区域(SGA...

    5.4.4 Enabling Automatic Shared Memory Management

    本节描述如果数据库实例当前启用了自动内存管理或手动共享内存管理,如何更改为自动共享内存管理。
    如果当前启用自动内存管理,则更改为自动共享内存管理:

    如果当前启用了自动内存管理,但您希望对系统全局区域(SGA)和实例程序全局区域(PGA)的大小有更直接的控制,则可以禁用自动内存管理并启用自动共享内存管理。遵循以下步骤:

    1. 在Oracle Enterprise Manager Database Express (EM Express)中,从Configuration菜单中选择初始化参数。
      将显示初始化参数页,并显示当前选项卡。

    2. 在搜索字段中,输入MEMORY_TARGET。

    3. 选择MEMORY_TARGET,然后单击Set。
      出现Set初始化参数页。

    4. 在Value字段中,输入0,指定内存范围,然后单击OK。
      出现一条确认消息。
      注意:
      此步骤将当前会话的自动内存管理更改为自动共享内存管理。将自动内存管理改为自动共享内存管理,并在数据库重启后保持有效:

      • 如果数据库使用服务器参数文件,请在设置初始化参数页上指定SPFile的作用域和内存的作用域。

      • 如果数据库使用文本初始化参数文件,则手动将该文件中的MEMORY_TARGET值设置为0.

    5. 从Configuration菜单中选择Memory。
      注意,在内存设置部分的SGA内存分区中,管理模式值现在是自动的。这表示启用了自动共享内存管理。页面上显示的初始化参数值是除MEMORY_TARGET之外指定的值。

      Description of auto_shared_mem_crop.gif follows
      Description of the illustration auto_shared_mem_crop.gif

    如果当前启用手动共享内存管理,则更改为自动共享内存管理:

    如果当前启用了手动共享内存管理,但是希望Oracle数据库帮助您确定SGA和实例PGA的最佳大小,则可以禁用手动共享内存管理并启用自动共享内存管理。遵循以下步骤:

    1. In SQL*Plus, run the following query in the database to obtain a value for SGA_TARGET:
      SELECT (
         (SELECT SUM(value) FROM V$SGA) -
         (SELECT CURRENT_SIZE FROM V$SGA_DYNAMIC_FREE_MEMORY)
         ) "SGA_TARGET"
      FROM DUAL;
      
      SGA_TARGET
      ----------
       371654656
      

      This value is approximately 354M.

    2. I在配置菜单中,选择初始化参数。
      将出现初始化参数页。
    3. In the Search field, enter SGA_TARGET.
    4. Select SGA_TARGET, and then click Set.

      The Set Initialization Parameter page appears.

    5. 在Value字段中,输入上面步骤1中的SGA_TARGET值(本例中为354M),指定内存范围,然后单击OK。

      Note:

      此步骤将当前会话的手动共享内存管理更改为自动共享内存管理。将手动共享内存管理改为自动共享内存管理,并在数据库重启后保持有效:

      • 如果数据库使用服务器参数文件,请在设置初始化参数页上指定SPFile的作用域和内存的作用域。

      • 如果数据库使用文本初始化参数文件,则手动将该文件中的MEMORY_TARGET值设置为0。

    6. 从Configuration菜单中选择Memory。
      注意,在内存设置部分的SGA内存分区中,管理模式值现在是自动的。这表示启用了自动共享内存管理。

      Description of auto_shared_mem_crop.gif follows
      Description of the illustration auto_shared_mem_crop.gif

    7. Do one of the following:
      • 为了更完整的自动调优,在初始化参数页面将下表中列出的自动调整大小的SGA组件的值设置为0:

        SGA Component Initialization Parameter

        The shared pool

        SHARED_POOL_SIZE

        The large pool

        LARGE_POOL_SIZE

        The Java pool

        JAVA_POOL_SIZE

        The buffer cache

        DB_CACHE_SIZE

        The Streams pool

        STREAMS_POOL_SIZE

      • 要控制一个或多个自动调整大小的SGA组件的最小大小,请将这些组件的大小设置为所需的值,如Oracle Database Administrator 's Guide中所述。在初始化参数页上将其他自动调整大小的SGA组件的值设置为零。

    5.4.5 Modifying Memory Settings – Automatic Shared Memory Management

    在修改用于自动共享内存管理的内存设置之前,请使用Oracle Enterprise Manager Database Express (EM Express)中的SGA Advisor图来预测使用不同的系统全局区域(SGA)大小节省的时间百分比。本节假设禁用了自动内存管理,并且启用了自动共享内存管理。

    预测不同SGA内存大小节省的时间百分比:

    1. 在EM Express中,从Configuration菜单中选择Memory。
      出现内存管理页面。在内存设置部分,管理模式值在SGA内存部分是自动的。这表明数据库启用了自动共享内存管理。
      使用SGA Advisor图(出现在内存设置部分右侧)预测为潜在的SGA内存大小节省的时间百分比。

      Description of sga_advisor_graph.gif follows
      Description of the illustration sga_advisor_graph.gif

      In the SGA Advisor graph:

      • SGA_TARGET初始化参数的潜在值(单位为MB)在图的横轴上表示。SGA_TARGET初始化参数的当前设置由一个蓝点表示。

      • 节省的时间值在图的纵轴上表示。绘制的值表示为相对于当前SGA_TARGET初始化参数设置的百分比。
        负值表示时间消耗增加的百分比(分配给Oracle的内存小于当前设置时),正值表示时间消耗减少的百分比(分配给Oracle的内存大于当前设置时)。

      图上的一条橙色线表示可以为sga_targetinitialize参数指定的不同值。单击橙色直线上的任何一个点,可以看到由该点表示的SGA_TARGET的时间消耗减少的预测。
      在此图中,SGA Advisor图表明,增加SGA_TARGET初始化参数的当前值不会减少节省的时间百分比。

    2. 要更改SGA_TARGET初始化参数的值:

      1. Click Configure Memory on the Memory Management page.

        The Initialization Parameter page appears.

      2. Select the SGA_TARGET initialization parameter and click Set.

        The Set Initialization Parameter page appears.

      3. In the Scope field, enter the scope for this change.

        See "Viewing and Modifying Initialization Parameters" for more information about setting a scope of Memory, or SPFile, or both.

      4. In the Value field, enter the new value for the SGA_TARGET initialization parameter.

      5. Click OK.

        A confirmation message appears.

    See Also:

    •  
    展开全文
  • 转载---Java 共享内存

    2014-07-25 17:03:57
    Java 共享内存 共享内存可以说是最有用的进程间通信方式,也是最快的IPC(Inter-Process Communication)形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址 空间。进程A可以...
  • 共享内存--函数

    千次阅读 2012-03-06 23:09:04
    共享内存允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间传递数据的一种非常有效的方式。大多数的共享内存的具体实现,都把由不同进程之间共享的内存安排为同一段物理内存。 共享内存...
  • PHP SESSION如果你是单机的服务,且又启用了session,那么可以把session换成共享内存的来存储,会比文件要快上不少,这里还要强调是单机,这是最大的软肋,但就功能上来讲没有memcache方便。什么是共享内存共享内存...
  • java共享内存

    2014-11-06 21:04:58
    这里提供的类文件mmap.java封装了共享内存的基本接口,读者可以用该类扩展成自己 需要的功能全面的类。 如果执行写操作的应用异常中止,那么映像文件的共享内存将不再能执行写操作。为了 在应用异常中止后,写...
  • 基于共享内存多级hash设计

    千次阅读 2015-09-06 10:37:37
    Feature list: 1. 支持Set/Get/Replace/Update, 优化编译下默认16级冲突下单进程下Set/Get可达170w次/s。(理论上只要不达到内容的带宽限制,而且...3. 支持CAS弱一致性检测(需要编译时开启) 4. 支持二进制文件导
  • 启用Oracle Enterprise Manager (EM) 内存参数 • 设置自动优化的内存参数 • 使用手动优化的SGA 参数覆盖最小大小 ...• 使用SGA Advisor 设置SGA_TARGET ...该幻灯片显示自动管理共享内存 (ASMM) 所涉及的关键
  • PHP 直接在共享内存中存储数据集

    千次阅读 2015-08-26 15:33:06
    共享内存是一种在相同机器中的应用程序之间交换数据的有效方式。一个进程可创建一个可供其他进程访问的内存段,只要它分配了正确的权限。每个内存段拥有一个惟一的 ID(称为 shmid),这个 ID 指向一个物理内存区域,...
  • 共享内存是IPC众多机制中的一种。它允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间传递数据的一种非常有效的方式。虽然X/Open标准并没有对它做出要求,但大多数共享内存的具体实现,...
  • 14.2 共享内存 共享内存是3个IPC机制中的第二个,它允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间传递数据的一种非常有效的方式.大多数共享内存的具体实现,都把由不同进程之间共享的...
  • 进程A: #include &lt;Windows.h&gt; HANDLE hMapFile = INVALID_HANDLE_VALUE;...LPVOID lpBase = NULL;...#define BUF_SIZE 8 //设置共享... //功能:采用共享内存方式将端口号写入内存中供客户端读取 cha...
  • 这里将共享内存句柄直接通过命令行参数传给子进程,子进程可直接获取到共享内存的地址   BOOL CreateProcess(  PCTSTR psApplicationName, //可执行文件的名字  PTSTR pszCommandLine, //命令行字符...
  • 1. 背景本文将介绍进程通信中的共享内存,信号量和套接字方法。2. 共享内存共享内存是最快的IPC(进程间通信)方式。共享内存是一个程序向内存写数据,另一个程序读数据,共享内存牵扯到同步的问题,一般有三种方案...
  • 共享内存实现 Redis(上)

    千次阅读 2017-09-18 09:25:13
    背景 Redis是一个应用广泛的开源NoSql数据库,在腾讯... 数据存放在私有内存,升级版本和更新困难,且危险性高(由于内部使用需要给Redis源码内嵌一些自研的库或针对实际需求做一些源码修改,不能直接使用原生Redis)
  • eaccelerator的功能除了对php预编译代码进行优化、缓存之外,还提供了php开发下的共享内存操作、session内存存储、内容缓存等功能。php默认的session存储方式是在磁盘,虽然可以配置php生成的文件目录到内存盘中,但...
  • Oracle 数据库 10g:自动共享内存管理

    千次阅读 2004-11-28 21:06:00
    自动共享内存管理特性使得自动将内存分配到最需要的地方去成为可能。无论您是一个刚入门的 DBA 还是一个经验丰富的 DBA,您肯定至少看到过一次类似以下的错误: ORA-04031:unable to allocate 2216 bytes of shared ...
  • 共享内存线程安全   func TestCounter(t *testing.T) { counter := 0 for i := 0; i ; i++ { go func() { counter++ }() } time.Sleep(1 * time.Second) t.Logf("counter = %d", counter) } //执行...
  • 首先服务进程建立一个共享内存,并把需要的功能以std::function注册到一个容器中保存,然后开启对命令事件的监听循环。  2.然后客户进程开启,把命令与数据都写入共享内存中,然后主动触发发送事件,并开始监听数据...
  • 转载声明:Java堆内存是线程共享的!面试官:你确定吗? Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或多或少的对JVM有一些了解。可以说,关于...
  • 本文主要分析内存以及I/O相关的系统调用和库函数的实现原理,根据原理给出在使用过程中需要注意的问题和优化的侧重点,本文涉及到的系统调用包括readahead,pread/pwrite,read/write,mmap,readv/writev,sendfile...
  • [性能] PHP之中使用共享内存进行高速数据更新的一种方案作者:HonestQiao 如果在你实际的应用之中,你确实需要高速数据更新的操作,那么我们认为你已经具备以下先决条件: 能够按照实际应用的需要而调整服务器 关于...
  • 内存数据库从范型上可以分为关系型内存数据库和键值型内存数据库。在实际应用中内存数据库主要是配合oracle或mysql等大型关系...本文首先比较FastDB、Memcached和Redis主流内存数据库的功能特性,再从性能上比较...
  • Java堆内存是线程共享的?

    千次阅读 2020-03-10 10:17:00
    Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或多或少的对JVM有一些了解。可以说,关于JVM的相关知识,基本是每个Java开发者必学的知识点,也是...
  • 并且,对于Linux所支持通信手段的不同实现版本(如对于共享内存来说,有Posix共享内存区以及System V共享内存区两个实现版本),将主要介绍Posix API。 linux下进程间通信的几种主要手段简介: ...
  • Java堆内存是线程共享的!面试官:你确定吗?

    千次阅读 多人点赞 2020-03-10 10:06:26
    Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或多或少的对JVM有一些了解。可以说,关于JVM的相关知识,基本是每个Java开发者必学的知识点,也是...
  • 在VirtualBox下安装CentOS7并开启共享路径在VirtualBox下安装CentOS7并开启共享路径 安装VirtualBox 创建虚拟机 安装Linux软件 linux设定网络 安装virtualBox工具包安装VirtualBox选择VirtualBox是因为看到Docker...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 152,129
精华内容 60,851
关键字:

如何启用共享内存功能