Linux内存映射

目录

背景

一、什么是内存映射?        

 二、mman函数

 1.权限问题

2.总线错误 

3.内存权限

4.读文件内容

5.映射与文件

 6.非法参数错误

 7.偏移量大小

 8.映射内存大小

8.1 申请6k,访问5k

8.2 申请2k,访问3k

8.3 返回值检查

三、内存映射实现

 四、匿名内存映射

 五、munmap函数

六、System V共享内存

1.ftok函数

2.shmget函数

 3.shmat函数

 4. system V 共享内存使用步骤


背景

        在传统的文件访问中,进程通常使用系统调用(例如open()read()write()close()等)来操作文件。这些系统调用允许进程打开文件、从文件中读取数据、向文件中写入数据以及关闭文件。这种方法需要通过系统调用在用户空间和内核空间之间进行数据传输,因此可能会产生一定的性能开销。  

        而使用内存映射技术,即将文件的内容映射到进程的虚拟内存空间中,使得进程可以直接访问内存而无需通过系统调用来读取或写入文件的内容。这样做可以提高文件访问的效率,因为读写文件的操作直接转化为对内存的操作,避免了频繁的系统调用。

        内存映射是一种将磁盘文件的内容映射到进程的虚拟内存空间中的技术。这意味着文件的内容被映射到进程的地址空间中,使得进程可以直接通过访问内存的方式来读取或写入文件的内容,而无需调用传统的read和write系统调用。这种方式能够提高对文件的访问效率,并且简化了对文件的操作。

内存映射的主要优点包括:

  1. 性能优势:由于文件内容直接映射到了内存中,因此读取文件的操作可以直接通过内存访问完成,避免了频繁的磁盘IO操作,从而提高了读取文件的速度。

  2. 简化操作:通过内存映射,文件被映射到了进程的地址空间中,进程可以像操作内存一样对文件进行读写,这样就简化了对文件的操作流程。

  3. 共享内存:多个进程可以共享同一个文件的内存映射,这样可以实现进程间的数据共享,而无需进行显式的数据传输。

一、什么是内存映射?        

        使一个磁盘文件与内存中的一个缓冲区相映射,进程可以像访问普通内存一样对文件进行访问,不必再调用read,write。

 二、mmap函数

 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);                

功能:创建共享内存映射

函数返回值:成功返回创建的映射区首地址,失败返回MAP_FAILED( ((void *) -1) ),设置errno值。

参数说明:


addr:指定要映射的内存地址,一般设置为 NULL 让操作系统自动选择合适的内存地址。length:必须>0。映射地址空间的字节数,它从被映射文件开头 offset 个字节开始算起。prot:指定共享内存的访问权限。
可取如下几个值的可选:PROT_READ(可读), PROT_WRITE(可写), PROT_EXEC(可执行),PROT_NONE(不可访问)。flags:由以下几个常值指定:MAP_SHARED(共享的),MAP_PRIVATE(私有的), MAP_ANONYMOUS(匿名映射,用于血缘关系进程间通信)MAP_FIXED(表示必须使用 start 参数作为开始地址,如果失败不进行修正),其中,MAP_SHARED , MAP_PRIVATE必选其一,而 MAP_FIXED 则不推荐使用。fd:表示要映射的文件句柄。如果匿名映射写-1。offset:表示映射文件的偏移量,一般设置为 0 表示从文件头部开始映射。

注意事项:

 1.权限问题

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>int main()
{void* addr;int fd;fd = open("test",O_RDONLY);if(fd < 0){perror("open");return 0;}
//	int len = lseek(fd,0,SEEK_END);addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);if(addr == MAP_FAILED){perror("mmap");return 0;}return 0;
}

 文件的打开权限是只读,运行结果为:Permission denied

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
mmap: Permission denied
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat mman.c

 文件打开权限修改为可读可写即可,因为PROT_READ | PROT_WRITE为可读可写,要求:

        当MAP_SHARED时,要求:映射区的权限应 <=文件打开的权限(出于对映射区的保护),如果不满足报非法参数(Invalid argument)错误。

2.总线错误 

        用于映射的文件大小必须>0,当映射文件大小为0时,指定非0大小创建映射区,访问映射地址会报总线错误

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>int main()
{void* addr;int fd;fd = open("test",O_RDWR);if(fd < 0){perror("open");return 0;}
//	int len = lseek(fd,0,SEEK_END);addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);if(addr == MAP_FAILED){perror("mmap");return 0;}memcpy(addr,"abcdefg",7);return 0;
}
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
Bus error (core dumped)
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 

test文件里为空, 不满足:用于映射的文件大小必须>0。直接在test里加个空格都行。

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat testlinux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
ablinux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 

文件足够大,就可以显示出abcdef:

ablinux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ls -l test
-rwxrwxrwx 1 root root 104 Mar  8 00:44 test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
abcdefg                                         

3.内存权限

	addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_PRIVATE,fd,0);

        当MAP_PRIVATE时候,mmap中的权限是对内存的限制,只需要文件有读权限即可,操作只在内存有效,不会写到物理磁盘,且不能在进程间共享。

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat testlinux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim test

4.读文件内容

        注意进行强制类型转换,不然会有警告。

	printf("read = %s\n",(char*)addr);	
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
abcdefg                            linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
read = abcdefg                            

5.映射与文件

        映射区的释放与文件关闭无关,只要映射建立成功,文件可以立即关闭。

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
999999999                          
int main()
{void* addr;int fd;fd = open("test",O_RDWR);if(fd < 0){perror("open");return 0;}
//	int len = lseek(fd,0,SEEK_END);addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);if(addr == MAP_FAILED){perror("mmap");return 0;}close(fd);memcpy(addr,"999999999",9);//	printf("read = %s\n",(char*)addr);	return 0;
}

 6.非法参数错误

        指定0大小创建映射区,报非法参数错误(Invalid argument)

	addr = mmap(NULL,0,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
mmap: Invalid argument
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 

可以通过lseek取文件大小:

int len = lseek(fd,0,SEEK_END);
printf("%d\n",len);
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ls -l test
-rwxrwxrwx 1 root root 51 Mar  8 01:20 test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
51
read = 999999999                          linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int filedes, off_t offset, int whence) ;

返回值:成功:返回文件新的偏移量(成功) 

lessk()函数的参数说明:
第一个参数是文件描述符;
第二个参数是偏移量,
参数 offset可正可负,负数时向文件开头偏移,正数相对于文件末尾偏移
第三个参数是有三个选项:
1.SEEK_SET:将文件指针偏移到传入字节数处(文件头开始偏移)
2.SEEK_CUR:将文件指针偏移到当前位置加上传入字节数处;((当前位置开始偏移)
3.SEEK_END:将文件指针偏移到文件末尾加上传入字节数处(作为拓展作用,必须再执行一次写操作)

 7.偏移量大小

        文件偏移量必须为0或者4K的整数倍(不是,会报非法参数Invalid argument错误)

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
最后一个参数是偏移量  
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
mmap: Invalid argument
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 
	addr = mmap(NULL,len,PROT_READ | PROT_WRITE,MAP_SHARED,fd,1);

 8.映射内存大小

        映射大小可以大于文件大小,但只能访问文件page的内存地址,否则报总线错误 ,超出映射的内存大小报段错误。

        实际是根据文件大小分配空间的,文件大小是51。你申请2k的空间,实际分配的是4k的空间,而你申请6k,实际分配的还是4k空间,所以报总线错误。

8.1 申请6k,访问5k
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
Bus error (core dumped)
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 
	addr = mmap(NULL,6000,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);memcpy((addr+5000),"999999999",9);
8.2 申请2k,访问3k
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
read = 999999999
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 
	addr = mmap(NULL,2000,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);memcpy((addr+3000),"999999999",9);

 

8.3 返回值检查

        mmap创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续操作。

    void* addr;    addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);if(addr == MAP_FAILED){perror("mmap");return 0;}

三、内存映射实现

 mmanw.c

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>int main()
{void* addr;int fd;fd = open("test",O_RDWR);if(fd < 0){perror("open");return 0;}int len = lseek(fd,0,SEEK_END);addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);if(addr == MAP_FAILED){perror("mmap");return 0;}close(fd);int i = 0;while(i<2048){memcpy((addr+i),"a",1);i++;sleep(1);}return 0;
}

mmanr.c

#include<stdio.h>#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>int main()
{void* addr;int fd;fd = open("test",O_RDWR);if(fd < 0){perror("open");return 0;}int len = lseek(fd,0,SEEK_END);addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);if(addr == MAP_FAILED){perror("mmap");return 0;}close(fd);while(1){printf("read = %s\n",(char*)(addr));sleep(1);}return 0;
}

 四、匿名内存映射

        void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);                

         fd:表示要映射的文件句柄。如果匿名映射写-1。

        匿名映射适用于具有亲缘关系的进程之间。

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mmap_n mmap_n.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mmap_n.c
./mmap_n.c: line 13: syntax error near unexpected token `('
./mmap_n.c: line 13: `int main()'
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mmap_n
read father value = 1234567890
#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>int main()
{void* addr;//匿名映射不需要文件操作addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,-1,0);if(addr == MAP_FAILED){perror("mmap");return 0;}pid_t pid;pid = fork();if(pid < 0){perror("pid");return 0;}else if(pid > 0){memcpy(addr,"1234567890",10);wait(NULL);}else{sleep(1);printf("read father value = %s\n",(char*)addr);}return 0;
}

        使用mmap函数创建一个大小为2048字节的共享内存区域。mmap的第一个参数是指定的映射地址(这里为NULL表示由系统决定),然后指定映射的大小为2048字节,设置读写权限为可读可写,使用MAP_SHARED标志来创建一个共享映射,MAP_ANONYMOUS标志表示不与任何文件关联 。

        使用fork函数创建一个子进程。如果fork返回负值,则表示创建失败,父进程会输出错误信息并退出。如果fork返回0,则表示当前代码运行在子进程中,子进程将等待1秒后,从共享内存中读取数据并打印输出。如果fork返回正值,则表示当前代码运行在父进程中,父进程使用memcpy将字符串"1234567890"复制到共享内存中,然后等待子进程结束。

为什么?

父进程在写入数据后,可能会导致子进程读取数据,
而如果父进程提前退出,操作系统会清理共享内存,
这可能导致子进程读取到的数据不完整或者无效。通过调用wait(NULL),父进程等待子进程执行完毕,
确保子进程能够正常读取共享内存中的数据。
只有在子进程执行完毕后,父进程才会继续执行后续的操作,包括退出程序,
这样就不会导致共享内存被提前清理。

 五、munmap函数

int munmap(void *addr, size_t length);​​​​​​​返回值:成功返回0,失败返回-1,并设置errno值。函数参数:addr:调用mmap函数成功返回的映射区首地址length:映射区大小(即:mmap函数的第二个参数)

        在进程地址空间中解除一个映射关系,addr是调用mmap()时返回的地址,len是映射区的大小。当映射关系解除后,对原来映射地址的访问将导致段错误发生。 

如下代码中该参数就是addr:

addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,-1,0);

六、System V共享内存

1.ftok函数

 key_t  ftok(const char *path,  int id);

        其中参数path是指定的文件名,这个文件必须是存在的而且可以访问的。id是子序号,它是一个8bit的整数。即范围是0~255当函数执行成功,则会返回key_t键值,否则返回-1。

#include<sys/types.h>
#include<sys/ipc.h>
#include<stdio.h>
int main()
{key_t key;key = ftok("keytest",100);if(key < 0){perror("ftok");return 0;}printf("key = %x\n",key);return 0;
}
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ vim ftok.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ touch keytest
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ls
ftok.c  keytest
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ gcc -o ftok ftok.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./ftok
key = 64180004
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ 

2.shmget函数

int shmget(key_t key, int size, int shmflg); 

第一个参数,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,shmget()函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1。

第二个参数,size以字节为单位指定需要共享的内存容量。

第三个参数,shmflg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。

#include<sys/types.h>
#include<sys/ipc.h>
#include<stdio.h>
int main()
{key_t key;key = ftok("keytest",100);if(key < 0){perror("ftok");return 0;}printf("key = %x\n",key);int shmid;shmid = shmget(key,512,IPC_CREAT | 0666);if(shmid < 0){perror("shmget");return 0;}printf("shmid = %d\n",shmid);return 0;}
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ gcc -o ftok1 ftok.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./ftok1
key = 64180004
shmid = 2064395
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ gcc -o ftok1 ftok.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./ftok1
key = 64180004
shmid = 2064395
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ipcs ------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 1376256    linux      600        524288     2          dest         
0x00000000 327681     linux      600        524288     2          dest         
0x00000000 524290     linux      600        524288     2          dest         
0x00000000 688131     linux      600        524288     2          dest         
0x00000000 1212420    linux      600        524288     2          dest         
0x00000000 1015813    linux      600        16777216   2                       
0x00000000 1048582    linux      600        33554432   2          dest         
0x00000000 1867783    linux      600        524288     2          dest         
0x00000000 1572872    linux      600        524288     2          dest         
0x00000000 1638409    linux      600        2097152    2          dest         
0x00000000 1900554    linux      600        1048576    2          dest         
0x64180004 2064395    linux      666        512        0                       ------ Semaphore Arrays --------
key        semid      owner      perms      nsems     ------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages 

 3.shmat函数

void *shmat(int shm_id, const void *shm_addr, int shmflg);

第一个参数,shm_id是由shmget()函数返回的共享内存标识。

第二个参数,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。

第三个参数,shm_flg是一组标志位,通常为0。

调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1。

 4. system V 共享内存使用步骤

        4.1创建/打开共享内存

        4.2映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问

        4.3 读写共享内存

        4.4 撤销共享内存映射

        4.5 删除共享内存对象

读写共享内存:

#include<sys/types.h>
#include<sys/ipc.h>
#include<stdio.h>
#include<string.h>int main()
{key_t key;key = ftok("keytest",100);if(key < 0){perror("ftok");return 0;}printf("key = %x\n",key);int shmid;shmid = shmget(key,512,0666);if(shmid < 0){perror("shmget");return 0;}printf("shmid = %d\n",shmid);char* buf;buf = (char*)shmat(shmid,NULL,0);if(buf<0){perror("shmat");return 0;}
//	strcpy(buf,"hello,world");	printf("share buf = %s\n",buf);return 0;}

可以多次读取: 

linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ gcc -o shm_r shm_r.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./shm_r
key = 6418001d
shmid = 2457612
share buf = hello,world
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./shm_r
key = 6418001d
shmid = 2457612
share buf = hello,world
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./shm_r
key = 6418001d
shmid = 2457612
share buf = hello,world
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./shm_r
key = 6418001d
shmid = 2457612
share buf = hello,world
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./shm_r
key = 6418001d
shmid = 2457612
share buf = hello,world

撤销后再次访问发生段错误:

	printf("share buf = %s\n",buf);shmdt(buf);printf("share buf = %s\n",buf);
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ vim shm_r.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ gcc -o test shm_r.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./test
key = 6418001d
shmid = 2457612
share buf = hello,world
Segmentation fault (core dumped)
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ 

但其实共享内存还存在:

linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ipcs------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 1376256    linux      600        524288     2          dest         
0x00000000 327681     linux      600        524288     2          dest         
0x00000000 524290     linux      600        524288     2          dest         
0x00000000 688131     linux      600        524288     2          dest         
0x00000000 1212420    linux      600        524288     2          dest         
0x00000000 1015813    linux      600        16777216   2                       
0x00000000 1048582    linux      600        33554432   2          dest         
0x00000000 1867783    linux      600        524288     2          dest         
0x00000000 1572872    linux      600        524288     2          dest         
0x00000000 1638409    linux      600        2097152    2          dest         
0x00000000 1900554    linux      600        1048576    2          dest         
0x64180004 2064395    linux      666        512        0                       
0x6418001d 2457612    linux      666        512        0      

需要删除共享内存,避免内存消耗:

int  shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl(shmid, IPC_RMID, NULL);删除共享内存
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ./test
key = 6418001d
shmid = 2457612
share buf = hello,world
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ vim shm_r.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ ipcs------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 1376256    linux      600        524288     2          dest         
0x00000000 327681     linux      600        524288     2          dest         
0x00000000 524290     linux      600        524288     2          dest         
0x00000000 688131     linux      600        524288     2          dest         
0x00000000 1212420    linux      600        524288     2          dest         
0x00000000 1015813    linux      600        16777216   2                       
0x00000000 1048582    linux      600        33554432   2          dest         
0x00000000 1867783    linux      600        524288     2          dest         
0x00000000 1572872    linux      600        524288     2          dest         
0x00000000 1638409    linux      600        2097152    2          dest         
0x00000000 1900554    linux      600        1048576    2          dest         
0x64180004 2064395    linux      666        512        0                       ------ Semaphore Arrays --------
key        semid      owner      perms      nsems     ------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    linux@linux:/mnt/hgfs/linuxshare/linux_code/system$ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/732591.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SSH移植到BusyBox

手动编译SSH安装挺麻烦的&#xff0c;本文主要是我大量借鉴和实践总结出来的流程&#xff0c;一步一按照做不会有太大问题。 移植平台&#xff1a;IMX6UL(迅为开发板) 根文件系统&#xff1a;BusyBox 所有操作都建议不要在root账户下运行&#xff0c;并且make install的安装路…

【Python】专栏文章索引

为了方便 快速定位 和 便于文章间的相互引用等 作为一个快速准确的导航工具 Python 目录&#xff1a; &#xff08;一&#xff09;装饰器函数 &#xff08;二&#xff09;牛客网—软件开发-Python专项练习 &#xff08;三&#xff09;装饰器函数 &#xff08;四&#xff0…

【深度学习】自动求导中有时为什么要先sum()再backward()

创作日志&#xff1a; 在看李沐学深度学习&#xff0c;“深度学习中&#xff0c;我们的目的不是计算微分矩阵&#xff0c;而是批量中每个样本单独计算的偏导数之和”&#xff0c;对这句话一知半解&#xff0c;自己动手推导一下。 一、理解 在深度学习中&#xff0c;被求导的对…

CSS的盒子模型:掌握网页设计的基石!

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Linux的进程调度实现

经常被问到进程的调度算法有哪些&#xff0c;什么先进先出、短进程优先、时间片轮转、多级反馈多列等等算法能说一大堆&#xff1f;那具体的&#xff0c;linux内核使用了什么样的算法&#xff0c;且来探究一下。 本文所引用源码基于linux内核2.6.34版本。 目录 调度器类 从 s…

探索 PostgreSQL 的高级数据类型 - 第 1 部分

数组和枚举 PostgreSQL 因其可扩展性和多功能性而备受欢迎&#xff0c;除了传统的整数和字符串之外&#xff0c;它还提供了多种数据类型。其中&#xff0c;包括数组和枚举&#xff0c;其为开发者提供了高级的数据建模能力。本文中&#xff0c;我们将深入研究这些复杂的数据类型…

Unity中PICO实现 隔空取物 和 接触抓取物体

文章目录 前言一、隔空取物1、XR Grab Interactable2、调节扔出去时的相关系数3、用手柄射线指向需要抓取的物体后&#xff0c;按下侧边扳机键即可抓取 二、接触抓取物体1、替换手柄上抓取物体的脚本2、在手柄上添加 接触抓取物体的脚本3、在手柄上添加碰撞盒触发器4、在需要抓…

PHAMB: 病毒数据分箱

Genome binning of viral entities from bulk metagenomics data | Nature Communications 安装 ### New dependencies *Recommended* conda install -c conda-forge mamba mamba create -n phamb python3.9 conda activate phamb mamba install -c conda-forge -c biocond…

IOS降级后从高版本到低版本恢复备份

IOS降级后从高版本到低版本恢复备份 此方法只适用于小版本还原&#xff0c;比如17.4->17.3&#xff0c;未验证大版本恢复可行性手机型号&#xff1a;iphone 13pro 系统版本&#xff1a;17.4 降级版本&#xff1a;17.3.1 步骤 通过itunes或者MacOS系统下对当前版本进行备份…

基于ThinkPHP框架的校园一卡通系统设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 相关技术 3 1.1 框架技术 3 1.1.1 Bootstrap 3 1.1.2 ThinkPHP框架 3 1.2 前端技术 4 1.2.1 JavaScript 4 1.2.2 ECharts 4 1.3 B/S架构 4 1.4 数据库技术 5 1.4.1 MySQL 5 1.5 本章小结 6 2 系统分析 7 2.1 功能需求分析 7 2.2 非功能需…

202441读书笔记|《笠翁对韵》—— 金菡萏,玉芙蓉,酒晕微酡琼杏颊,香尘浅印玉莲双

202441读书笔记|《笠翁对韵》——金菡萏&#xff0c;玉芙蓉&#xff0c;酒晕微酡琼杏颊&#xff0c;香尘浅印玉莲双 《作家榜名著&#xff1a;笠翁对韵》作者李渔&#xff0c;霍俊明。是所有词句都有注音的一本书&#xff0c;轻松学不认识的字&#xff0c;非常朗朗上口的对偶词…

PromptBreeder---针对特定领域演化和发展提示词的方法

原文地址&#xff1a;promptbreeder-evolves-adapts-prompts-for-a-given-domain 论文地址&#xff1a;https://arxiv.org/pdf/2309.16797.pdf 2023 年 10 月 6 日 提示方法分为两大类 硬提示是由人工精心设计的文本提示&#xff0c;包含离散的输入令牌&#xff1b;其缺点…

【Linux】gcc与make、makefile

文章目录 1 gcc/g1.1 预处理1.2 编译1.3 汇编1.4 链接1.4.1 静态链接1.4.2 动态链接 2 make和makefile2.1 依赖关系2.2 依赖方法2.3 伪目标 3 总结 1 gcc/g 当我们创建一个文件&#xff0c;并向里面写入代码&#xff0c;此时&#xff0c;我们该如何使我们的代码能够运行起来呢&…

html--心花怒放

代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>Canvas 绘制一个❤</title><link rel"shortcut icon" href"../../assets/images/icon/favicon.ico" type"ima…

C#实现快速排序算法

C#实现快速排序算法 以下是C#中的快速排序算法实现示例&#xff1a; using System;class QuickSort {// 快速排序入口函数public static void Sort(int[] array){QuickSortRecursive(array, 0, array.Length - 1);}// 递归函数实现快速排序private static void QuickSortRecu…

ubuntu自带屏幕截图功能

目录 简介开始截屏步骤1.打开截屏软件2.选择区域3.截图 快捷键 录屏方法11.开始录屏2.停止录屏 方法2 补充说明 简介 试了好多开源跨平台截图软件&#xff0c;但是在ubuntu上都或多或少存在问题。ubuntu有自带的截图软件。打算把ubuntu自带的截图软件用起来。 顺便说一下我使…

B端系统升级,登录页必在升级之列,不容置疑。

进行B端界面升级时&#xff0c;首先升级登录页有以下几个原因&#xff1a; 用户体验&#xff1a;登录页是用户进入系统的第一个页面&#xff0c;用户首先接触到的界面。通过升级登录页&#xff0c;可以提升用户的第一印象&#xff0c;增强用户对系统的信任感和好感度&#xff…

Android Studio编译及调试知识

文章目录 Android Studio编译kotlin项目Android Studio编译Java和kotlin混合项目的过程gradle打印详细错误信息&#xff0c;类似这种工具的使用Android apk 从你的代码到APK打包的过程&#xff0c;APK安装到你的Android手机上的过程&#xff0c;最后安装好的形态&#xff0c;以…

简单形状点云轮廓点排序(旋转角)

1、背景介绍 很多边缘提取算法提取的边缘点为无序点云&#xff0c;如下图所示&#xff0c;无序点云不利于后续各种应用&#xff0c;比如根据边缘计算点云面积、点云轮廓线规则化等。若对点云进行排序&#xff0c;则可以进行上述引用。但实际上&#xff0c;点云形状错综复杂&…

Dubbo 和 Zookeeper 的关系

Dubbo 和 Zookeeper 的关系 Zookeeper的作用 zookeeper用来注册服务和进行负载均衡&#xff0c;哪一个服务由哪一个机器来提供必需让调用者知道&#xff0c;简 单来说就是ip地址和服务名称的对应关系。当然也可以通过硬编码的方式把这种对应关系在调用方 业务代码中实现&#…