首页 > 系统相关 >无涯教程-进程 - 内存映射

无涯教程-进程 - 内存映射

时间:2023-08-27 14:01:52浏览次数:56  
标签:映射 int mmap 无涯 内存 进程 include

mmap()系统调用提供了将文件或设备映射到内存的调用进程的虚拟地址空间中的映射。这有两种类型-

文件映射  -  此映射将进程的虚拟内存区域映射到文件,这意味着读取或写入那些内存区域会导致文件被读取或写入,这是默认的映射类型。

匿名映射  -  此映射进程的虚拟内存区域,没有任何文件支持,内容被初始化为零。此映射类似于动态内存分配(malloc()),并在某些malloc()实现中用于某些分配。

一个进程映射中的内存可以与其他进程中的映射共享,这可以通过两种方式完成-

  • 当两个进程映射文件的同一区域时,它们共享相同的物理内存页面。

  • 如果创建了子进程,则该子进程将继承父进程的映射,并且这些映射所引用的物理内存页面与父进程相同,子进程中的任何数据更改后,都会为子进程创建不同的页面。

当两个或多个进程共享同一页面时,每个进程可以看到其他进程根据映射类型所做的页面内容更改,映射类型可以是私有的或共享的-

  • 私有映射(MAP_PRIVATE)  -  此映射内容的修改对其他进程不可见,并且该映射未携带到基础文件。

  • 共享映射(MAP_SHARED)   -  对此映射内容的修改对其他进程可见,并且映射被携带到基础文件中。

#include <sys/mman.h>

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

上面的系统调用成功时返回映射的起始地址,错误时返回MAP_FAILED。

#include <sys/mman.h>

int munmap(void *addr, size_t length);

上面的系统调用成功返回0或错误返回-1。

系统调用munmap执行已内存映射区域的取消映射,字段addr指示映射的起始地址,长度指示要映射的映射的字节大小。通常,映射和取消映射将针对整个映射区域。如果必须不同,则应将其缩小或切成两部分。如果地址没有任何映射,则此调用无效,并且该调用返回0(成功)。

让我们考虑一个例子-

步骤1  -  如下所示,写入文件字母数字字符-

0 1 2 ... 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ... 59 60 61
A B C ... Z 0 1 2 3 4 5 6 7 8 9 A b c ... x y z

步骤2  -  使用mmap()系统调用将文件内容映射到内存中,映射到内存后,它将返回起始地址。

步骤3  -  使用数组表示法访问文件内容(也可以使用指针表示法进行访问),因为它不会读取read()系统调用。使用内存映射,避免在用户空间,内核空间缓冲区和缓冲区高速缓存之间进行多次复制。

步骤4  -  重复读取文件内容,直到用户输入" -1"(表示访问结束)。

步骤5  -  执行清理活动,即取消映射映射的内存区域(munmap()),关闭文件并删除文件。

/* Filename: mmap_test.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
void write_mmap_sample_data();

int main() {
   struct stat mmapstat;
   char *data;
   int minbyteindex;
   int maxbyteindex;
   int offset;
   int fd;
   int unmapstatus;
   write_mmap_sample_data();
   if (stat("MMAP_DATA.txt", &mmapstat) == -1) {
      perror("stat failure");
      return 1;
   }
   
   if ((fd = open("MMAP_DATA.txt", O_RDONLY)) == -1) {
      perror("open failure");
      return 1;
   }
   data = mmap((caddr_t)0, mmapstat.st_size, PROT_READ, MAP_SHARED, fd, 0);
   
   if (data == (caddr_t)(-1)) {
      perror("mmap failure");
      return 1;
   }
   minbyteindex = 0;
   maxbyteindex = mmapstat.st_size - 1;
   
   do {
      printf("Enter -1 to quit or ");
      printf("enter a number between %d and %d: ", minbyteindex, maxbyteindex);
      scanf("%d",&offset);
      if ( (offset >= 0) && (offset <= maxbyteindex) )
      printf("Received char at %d is %c\n", offset, data[offset]);
      else if (offset != -1)
      printf("Received invalid index %d\n", offset);
   } while (offset != -1);
   unmapstatus = munmap(data, mmapstat.st_size);
   
   if (unmapstatus == -1) {
      perror("munmap failure");
      return 1;
   }
   close(fd);
   system("rm -f MMAP_DATA.txt");
   return 0;
}

void write_mmap_sample_data() {
   int fd;
   char ch;
   struct stat textfilestat;
   fd = open("MMAP_DATA.txt", O_CREAT|O_TRUNC|O_WRONLY, 0666);
   if (fd == -1) {
      perror("File open error ");
      return;
   }
   //Write A to Z
   ch = 'A';
   
   while (ch <= 'Z') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   //Write 0 to 9
   ch = '0';
   
   while (ch <= '9') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   //Write a to z
   ch = 'a';
   
   while (ch <= 'z') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   close(fd);
   return;
}
Enter -1 to quit or enter a number between 0 and 61: 3 
Received char at 3 is D 
Enter -1 to quit or enter a number between 0 and 61: 28
Received char at 28 is 2 
Enter -1 to quit or enter a number between 0 and 61: 38 
Received char at 38 is c 
Enter -1 to quit or enter a number between 0 and 61: 59 
Received char at 59 is x 
Enter -1 to quit or enter a number between 0 and 61: 65 
Received invalid index 65 
Enter -1 to quit or enter a number between 0 and 61: -99 
Received invalid index -99 
Enter -1 to quit or enter a number between 0 and 61: -1

参考链接

https://www.learnfk.com/process/inter-process-communication-memory-mapping.html

标签:映射,int,mmap,无涯,内存,进程,include
From: https://blog.51cto.com/u_14033984/7253112

相关文章

  • 无涯教程-进程 - 信号(Signals)
    信号是对进程的通知,指示事件的发生。信号也称为软件中断,无法预知其发生,因此也称为异步事件。可以用数字或名称指定信号,通常信号名称以SIG开头。可用信号kill–l(列出信号名称为l)检查可用信号,如下所示-无论何时发出信号,都会执行默认操作,忽略信号意味着既不执行默认操作也不处......
  • WinDbg排查.net性能或内存问题步骤简述
    目录一、安装WinDbg二、诊断数据获取三、加载分析四、举例分析以下步骤是分析高CPU占用的命令本文摘自一、安装WinDbg第一步当然是安装了,需要注意的是,千万不要搜索windbg然后下载,搜索到的windbg安装文件,都不是我们想要的,真正的windbg,实际上是在微软的SDK里,下载链接在这里:ht......
  • hibernate——一对一映射(1)
    一对一映射本来以为挺简单的,但是一接触发现还是有些琢磨头的,但是理解之后,才会发现原来是挺简单的。一对一映射关系,也有一个主表和从表的概念,例如人和身份证就是一对一的关系,如果将IdCard的主键设为Person的主键,那么Person为主表,而IdCard为从表,这样的映射关系决定了从表不能单独存在......
  • hibernate——多对一和一对多映射浅析
    首先应该清楚多对一和一对多只是站在不同的角度看待问题,其本质是一样的。在思考这个问题的时候,不要把这两个概念混在一起,这样不容易理解,而要分开,站在不同的角度去解决同一个问题。就拿员工和部门的例子来说,我们站在不同的角度,可能会遇到如下的几种情况:站在员工的角度看,是多对一的关......
  • 无涯教程-进程 - 消息队列
    使用消息队列的通信可以通过以下方式进行:通过一个进程写入共享内存,并通过另一个进程从共享内存读取。我们知道,读取也可以通过多个进程完成。由具有不同数据包的一个进程写入共享内存,并由多个进程(即根据消息类型)从共享内存中读取。看完消息队列上的某些信息后,现在该检查支持消......
  • 动态内存函数
    1.为什么存在动态内存分配?我们已经掌握的内存开辟方式有:int val=20;//在栈空间上开辟四个字节char arr[10]={0};//在栈空间上开局但是上述的开辟空间的方式有两个特点1.空间开辟大小是固定的。2.数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。但是对于空间的需......
  • 一次Java内存占用高的排查案例,解释了我对内存问题的所有疑问
    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,非公众号转载保留此声明。问题现象7月25号,我们一服务的内存占用较高,约13G,容器总内存16G,占用约85%,触发了内存报警(阈值85%),而我们是按容器内存60%(9.6G)的比例配置的JVM堆内存。看了下其它服务,同样的堆内存配置,它们内存占用约70%~79%,......
  • 无涯教程-进程 - 管道(Pipes)
    管道是两个或多个相关进程之间的通信介质,它可以在一个进程内,也可以在子进程与父进程之间进行通信。可以实时查看管道机制,例如用管道将水填充到某个容器(例如桶)中,然后取回某人(例如用杯子)。填充进程只不过是写入管道,而读取进程只不过是从管道中检索,这意味着一个输出(水)被输入......
  • 浮点数在内存中的存储形式
       大家都知道浮点数是什么,那他在内存中是怎么存储的呢?根据国际标准IEEE754规定中,任意一个二进制浮点数v可以表示成下面的形式:(-1)S*M*2E(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。M表示有效数字,大于等于1,小于2.2^E表示指数位。   那怎么来理解这段话呢,我们举个例......
  • 无涯教程-进程 - 其它进程
    到目前为止,我们已经讨论了进程,进程的创建,父进程和子进程等。如果不讨论其他相关进程(如孤立进程,僵尸进程和守护进程),则将是不完整的。孤立进程当我们运行程序或应用程序时,该应用程序的父进程是shell,当我们使用fork()创建进程时,新创建的进程是子进程,而创建子进程的进程是父进程......