iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >什么是虚拟映射和mmap()
  • 298
分享到

什么是虚拟映射和mmap()

2023-06-16 18:06:18 298人浏览 独家记忆
摘要

这篇文章给大家介绍什么是虚拟映射和mmap(),内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。虚存映射我们知道,程序是存储在磁盘上到静态文件;进程是对程序到一次运行过程。在进程开始运行时,进程的代码和数据等内容必须装入到

这篇文章给大家介绍什么是虚拟映射和mmap(),内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

虚存映射

我们知道,程序是存储在磁盘上到静态文件;进程是对程序到一次运行过程。在进程开始运行时,进程的代码和数据等内容必须装入到进程用户空间到适当区域。这些区域也就是所谓的代码段和数据段等,而被装入的数据和代码等内容被称为进程的可执行映像。从上面都描述中可以发现,进程在运行时并不是将程序一下子就装入到物理内存,而只是将程序装入到进程的用户空间,这个装入的过程称为虚存映射。

一个源程序在成为可执行文件的过程中会经历预处理、编译、汇编和链接四个阶段。因此,进程要成功运行不仅要在其用户空间装入进程映像,也要装入该进程所用到到函数库以及链接程序等。所以,一个进程到用户空间就被分为若干个内存区域。linux使用mm_struct结构来描述一个进程到用户地址空间,使用vm_area_struct结构来描述进程地址空间中的一个内存区域。因此,一个vm_area_struct结构可能代表进程到数据段,也可能代表链接程序到代码段等。

进程的虚存映射所做的只是将磁盘上到文件映射到该进程的用户地址空间,并没有建立虚拟内存到物理内存的映射。当某个可执行映像映射到进程用户空间并开始执行时,只有很少一部分虚拟页被装入了物理内存。在进程后续到执行过程中,如果需要访问到数据并不在物理内存中,则产生一个缺页中断(其实是异常),将所需页从交换区或磁盘中调入物理内存,这个过程即虚拟内存中到请页机制。

进程到虚存区

那么对于一个任意的进程,我们可以通过下面到方法查看其地址空间中到内存区域。

我们先看一个简单的测试程序:

#include < stdio.h >    #include < stdlib.h >      int main()    {     int i=1;     char *str=NULL;     printf("hello,world!\n");     str=(char *)malloc(sizeof(char)*1119);     sleep(1000);     return 0;    }

这个程序中使用到了malloc函数,因此str变量存储于堆中。我们通过打印/proc/3530/maps文件,即可看到该进程的内存空间划分。其中3530是该进程的id。

edsionte@edsionte-desktop:~$ cat /proc/3530/maps    0014a000-00165000 r-xp 00000000 08:07 398276 /lib/ld-2.11.1.so    00165000-00166000 r--p 0001a000 08:07 398276 /lib/ld-2.11.1.so    00166000-00167000 rw-p 0001b000 08:07 398276 /lib/ld-2.11.1.so    001d8000-0032b000 r-xp 00000000 08:07 421931 /lib/tls/i686/cmov/libc-2.11.1.so    0032b000-0032c000 ---p 00153000 08:07 421931 /lib/tls/i686/cmov/libc-2.11.1.so    0032c000-0032e000 r--p 00153000 08:07 421931 /lib/tls/i686/cmov/libc-2.11.1.so    0032e000-0032f000 rw-p 00155000 08:07 421931 /lib/tls/i686/cmov/libc-2.11.1.so    0032f000-00332000 rw-p 00000000 00:00 0    00441000-00442000 r-xp 00000000 00:00 0 [vdso]    08048000-08049000 r-xp 00000000 08:09 326401 /home/edsionte/test    08049000-0804a000 r--p 00000000 08:09 326401 /home/edsionte/test    0804a000-0804b000 rw-p 00001000 08:09 326401 /home/edsionte/test    08958000-08979000 rw-p 00000000 00:00 0 [heap]    b78ce000-b78cf000 rw-p 00000000 00:00 0    b78dd000-b78e0000 rw-p 00000000 00:00 0    bfa6a000-bfa7f000 rw-p 00000000 00:00 0 [stack]

每一行信息依次显示的内容为内存区域其实地址-终止地址,访问权限,偏移量,主设备号:次设备号,inode,文件。

上面的信息不但包含了test可执行对象的各内存区域,而且还分别显示了 /lib/ld-2.11.1.so(动态连接程序)文件和/lib/tls/i686/cmov/libc-2.11.1.so(C库)文件的内存区域信息。

我们从某个内存区域的访问权限上可以大致判断该区域的类型。各个属性符号的意义为:r-read,w-write,x-execute,s-shared,p-private。因此,r-x一般代表程序的代码段,即可读,可执行。rw-可能代表数据段,BSS段和堆栈段等,即可读,可写。堆栈段从行信息的文件名就可以区分;如果某行信息的文件名为空,那么可能是BSS段。另外,上述test进程共享了内核动态库,所以在00441000-00442000行处文件名显示为vdso(Virtual Dynamic Shared Object)。

mmap系统调用

通过mmap系统调用可以在进程到用户空间中创建一个新到虚存区。该系统调用到原型如下:

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

该函数可以将以打开的文件映射到进程用户空间到一片内存区上,执行成功后,该函数返回这段映射区到首地址。用户得到这片虚存的首地址后,就可以像访问内存那样访问文件。

该系统调用的参数说明如下:

addr:映射到用户地址空间到起始地址;

length:映射区以字节为单位到长度;

prot:对映射区到访问模式。包括PROT_EXEC(可执行),PROT_READ (可读),PROT_WRITE(可写),PROT_NONE(文件不可访问)。这个访问模式不能超过所映射文件到打开模式。比如被映射的文件打开模式为只读,那么此处到访问模式不能是可读写的。

flags:这个字段比较灵活,不同到标志有不同的功能,具体如下:

MAP_SHARED:创建一个可被子进程共享的映射区;

MAP_PRIVATE:创建一个“写实复制”的映射区;

MAP_ANONYMOUS:创建一个匿名到映射区,该虚存区与进程无关;

fd:所要映射到进程用户空间的文件描述符,该文件必须为以打开的文件;

offset:文件的起始映射偏移量;

mmap()举例

在该程序中,首先以只读方式打开文件test.c,再通过该文件返回到文件描述符和mmap函数将test.c文件映射到当前进程到用户地址空间中。成功执行mmap函数后,buf被赋值为所映射的虚存区的首地址。注意,mmap函数返回的是void型指针,而buf是char型指针。将mmap返回值赋值给buf变量时,自动将void*转化为char*型。

***,就像平常我们使用一个char型指针变量那样,依次打印出buf中到数据。

 #include < stdio.h >     #include < sys/mman.h >     #include < fcntl.h >     int main()     {     int i,fd;     char *buf = NULL;     fd = open("./test.c", O_RDONLY);     if(fd < 0)     {     printf("open error\n");     return -1;     }     buf = mmap(NULL, 12, PROT_READ, MAP_PRIVATE ,fd, 0);     for(i = 0;i < 12;i++)     {     printf("%c",buf[i]);     }     printf("\n");     return 0;    }

关于什么是虚拟映射和mmap()就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: 什么是虚拟映射和mmap()

本文链接: https://www.lsjlt.com/news/284600.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c++中if elseif使用规则
    c++ 中 if-else if 语句的使用规则为:语法:if (条件1) { // 执行代码块 1} else if (条件 2) { // 执行代码块 2}// ...else ...
    99+
    2024-05-14
    c++
  • c++中的继承怎么写
    继承是一种允许类从现有类派生并访问其成员的强大机制。在 c++ 中,继承类型包括:单继承:一个子类从一个基类继承。多继承:一个子类从多个基类继承。层次继承:多个子类从同一个基类继承。多层...
    99+
    2024-05-14
    c++
  • c++中如何使用类和对象掌握目标
    在 c++ 中创建类和对象:使用 class 关键字定义类,包含数据成员和方法。使用对象名称和类名称创建对象。访问权限包括:公有、受保护和私有。数据成员是类的变量,每个对象拥有自己的副本...
    99+
    2024-05-14
    c++
  • c++中优先级是什么意思
    c++ 中的优先级规则:优先级高的操作符先执行,相同优先级的从左到右执行,括号可改变执行顺序。操作符优先级表包含从最高到最低的优先级列表,其中赋值运算符具有最低优先级。通过了解优先级,可...
    99+
    2024-05-14
    c++
  • c++中a+是什么意思
    c++ 中的 a+ 运算符表示自增运算符,用于将变量递增 1 并将结果存储在同一变量中。语法为 a++,用法包括循环和计数器。它可与后置递增运算符 ++a 交换使用,后者在表达式求值后递...
    99+
    2024-05-14
    c++
  • c++中a.b什么意思
    c++kquote>“a.b”表示对象“a”的成员“b”,用于访问对象成员,可用“对象名.成员名”的语法。它还可以用于访问嵌套成员,如“对象名.嵌套成员名.成员名”的语法。 c++...
    99+
    2024-05-14
    c++
  • C++ 并发编程库的优缺点
    c++++ 提供了多种并发编程库,满足不同场景下的需求。线程库 (std::thread) 易于使用但开销大;异步库 (std::async) 可异步执行任务,但 api 复杂;协程库 ...
    99+
    2024-05-14
    c++ 并发编程
  • 如何在 Golang 中备份数据库?
    在 golang 中备份数据库对于保护数据至关重要。可以使用标准库中的 database/sql 包,或第三方包如 github.com/go-sql-driver/mysql。具体步骤...
    99+
    2024-05-14
    golang 数据库备份 mysql git 标准库
  • 如何在 Golang 中优雅地处理错误?
    在 go 中,优雅处理错误包括:使用 error 类型;使用 errors 包函数和类型;自定义错误类型;遵循错误处理模式,包括关闭资源、检查错误、打印错误信息和处理或返回错误。 在 ...
    99+
    2024-05-14
    golang 错误处理
  • 如何构建 Golang RESTful API,并使用中间件进行身份验证?
    本文介绍了如何构建 golang restful api。首先,通过导入必要的库、定义数据模型和创建路由来构建 restful api。其次,使用 go-chi/chigot 和 go-...
    99+
    2024-05-14
    golang git
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作