Linux的mmap文件内存映射机制
更新时间:2024-04-24 23:26:01 阅读量: 综合文库 文档下载
Linux的mmap文件内存映射机制
在讲述文件映射的概念时,不可避免的要牵涉到虚存(SVR 4的VM)。实际上,文件映射是虚存的中心概念,文件映射一方面给用户提供了一组措施,好似用户将文件映射到自己地址空间的某个部分,使用简单的内存访问指令读写文件;另一方面,它也可以用于内核的基本组织模式,在这种模式中,内核将整个地址空间视为诸如文件之类的一组不同对象的映射。Linux中的传统文件访问方式是, 首先用open系统调用打开文件,然后使用read,write以及lseek等调用进行顺序或者随即的I/O.这种方式是非常低效的,每一次I/O操作都需要一次系统调用。另外,如果若干个进程访问同一个文件,每个进程都要在自己的地址空间维护一个副本,浪费了内存空间。而如果能够通过一定的机制将页面映射到进程的地址空间中,也就是说首先通过简单的产生某些内存管理数据结构完成映射的创建。当进程访问页面时产生一个缺页中断,内核将页面读入内存并且更新页表指向该页面。而且这种方式非常方便于同一副本的共享。
VM是面向对象的方法设计的,这里的对象是指内存对象:内存对象是一个软件抽象的概念,它描述内存区与后备存储之间的映射。系统可以使用多种类型的后备存储,比如交换空间,本地或者远程文件以及帧缓存等等。VM系统对它们统一处理,采用同一操作集操作,比如读取页面或者回写页面等。每种不同的后备存储都可以用不同的方法实现这些操作。这样,系统定义了一套统一的接口, 每种后备存储给出自己的实现方法。进程的地址空间就被视为一组映射到不同数据对象上的的映射组成。所有的有效地址就是那些映射到数据对象上的地址。 这些对象为映射它的页面提供了持久性的后备存储。映射使得用户可以直接寻址这些对象。
值得提出的是,VM体系结构独立于Unix系统,所有的Unix系统语义,如正文,数据及堆栈区都可以建构在基本VM系统之上。同时,VM体系结构也是独立于存储管理的,存储管理是由操作系统实施的,如:究竟采取什么样的对换和请求调页算法,究竟是采取分段还是分页机制进行存储管理,究竟是如何将虚拟地址转换成为物理地址等等(Linux中是一种叫Three Level Page Table的机制),这些都与内存对象的概念无关。
下面介绍Linux中 VM的实现。
一个进程应该包括一个mm_struct(memory manage struct), 该结构是进程虚拟地址空间的抽象描述, 里面包括了进程虚拟空间的一些管理信息: start_code, end_code, start_data, end_data, start_brk, end_brk等等信息。 另外, 也有一个指向进程虚存区表(vm_area_struct: virtual memory area)的指针, 该链是按照虚拟地址的增长顺序排列的。 在Linux进程的地址空间被分作许多区(vma), 每个区(vma)都对应虚拟地址空间上一段连续的区域, vma是可以被共享和保护的独立实体, 这里的vma就是前面提到的内存对象。 下面是vm_area_struct的结构, 其中, 前半部分是公共的, 与类型无关的一些数据成员, 如: 指向mm_struct的指针, 地址范围等等, 后半部分则是与类型相关的成员, 其中最重要的是一个指向vm_operation_struct向量表的指针vm_ops, vm_ops向量表是一组虚函数, 定义了与vma类型无关的接口。 每一个特定的子类, 即每种vma类型都必须在向量表中实现这些操作。 这里包括了: open, close, unmap, protect, sync, nopage, wppage, swapout这些操作。
struct vm_area_struct {
/*公共的, 与vma类型无关的 */ struct mm_struct * vm_mm; unsigned long vm_start; unsigned long vm_end;
struct vm_area_struct *vm_next; pgprot_t vm_page_prot; unsigned long vm_flags; short vm_avl_height;
struct vm_area_struct * vm_avl_left; struct vm_area_struct * vm_avl_right; struct vm_area_struct *vm_next_share; struct vm_area_struct **vm_pprev_share; /* 与类型相关的 */
struct vm_operations_struct * vm_ops; unsigned long vm_pgoff; struct file * vm_file; unsigned long vm_raend; void * vm_private_data; };
vm_ops: open, close, no_page, swapin, swapout??
介绍完VM的基本概念后, 我们可以讲述mmap和munmap系统调用了。 mmap调用实际上就是一个内存对象vma的创建过程, mmap的调用格式是:void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);其中start是映射地址, length是映射长度, 如果flags的MAP_FIXED不被置位, 则该参数通常被忽略, 而查找进程地址空间中第一个长度符合的空闲区域;Fd是映射文件的文件句柄, offset是映射文件中的偏移地址;prot是映射保护权限, 可以是PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE, flags则是指映射类型, 可以是MAP_FIXED, MAP_PRIVATE, MAP_SHARED, 该参数必须被指定为MAP_PRIVATE和MAP_SHARED其中之一, MAP_PRIVATE 是创建一个写时拷贝映射(copy-on-write), 也就是说如果有多个进程同时映射到一个文件上, 映射建立时只是共享同样的存储页面, 但是某进程企图修改页面内容, 则复制一个副本给该进程私用, 它的任何修改对其它进程都不可见。 而MAP_SHARED则无论修改与否都使用同一副本, 任何进程对页面的修改对其它进程都是可见的。
mmap系统调用的实现过程是: 1.先通过文件系统定位要映射的文件;
2.权限检查, 映射的权限不会超过文件打开的方式, 也就是说如果文件是以只读方式打开, 那么则不允许建立一个可写映射;
3.创建一个vma对象, 并对之进行初始化;
4.调用映射文件的mmap函数, 其主要工作是给vm_ops向量表赋值; 5.把该vma链入该进程的vma链表中, 如果可以和前后的vma合并则合并; 6.如果是要求VM_LOCKED(映射区不被换出)方式映射, 则发出缺页请求,
把映射页面读入内存中。
munmap(void * start, size_t length):该调用可以看作是 mmap的一个逆过程。 它将进程中从start开始length长度的一段区域的映射关闭, 如果该区域不是恰好对应一个vma, 则有可能会分割几个或几个vma.
msync(void * start, size_t length, int flags):把映射区域的修改回写到后备存储中。 因为munmap时并不保证页面回写, 如果不调用msync, 那么有可能在munmap后丢失对映射区的修改。 其中flags可以是MS_SYNC, MS_ASYNC, MS_INVALIDATE, MS_SYNC要求回写完成后才返回, MS_ASYNC发出回写请求后立即返回, MS_INVALIDATE使用回写的内容更新该文件的其它映射。 该系统调用是通过调用映射文件的sync函数来完成工作的。
brk(void * end_data_segement):将进程的数据段扩展到 end_data_segement指定的地址, 该系统调用和mmap的实现方式十分相似, 同样是产生一个vma, 然后指定其属性。 不过在此之前需要做一些合法性检查, 比如该地址是否大于mm->end_code, end_data_segement和mm->brk之间是否还存在其它vma等等。 通过brk产生的vma映射的文件为空, 这和匿名映射产生的vma相似, 关于匿名映射不做进一步介绍。 库函数malloc就是通过brk实现的。
Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明:
头文件:
原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offsize);
返回值: 成功则返回映射区起始地址, 失败则返回MAP_FAILED(-1)。 参数:addr: 指定映射的起始地址, 通常设为NULL, 由系统指定。 length: 将文件的多大长度映射到内存。
prot: 映射区的保护方式, 可以是: PROT_EXEC: 映射区可被执行。
PROT_READ: 映射区可被读取。 PROT_WRITE: 映射区可被写入。
PROT_NONE: 映射区不能存取。
flags: 映射区的特性, 可以是:
MAP_SHARED: 对映射区域的写入数据会复制回文件, 且允许其他映射该文件的进程共享。
MAP_PRIVATE: 对映射区域的写入操作会产生一个映射的复制(copy-on-write), 对此区域所做的修改不会写回原文件。 此外还有其他几个flags不很常用, 具体查看linux C函数说明。 fd: 由open返回的文件描述符, 代表要映射的文件。
offset: 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射。
下面说一下内存映射的步骤:
1、用open系统调用打开文件, 并返回描述符fd.
2、用mmap建立内存映射, 并返回映射首地址指针start.对映射(文件)进行各种操作, 显示(printf), 修改(sprintf)。 3、用munmap(void *start, size_t lenght)关闭内存映射。 4、用close系统调用关闭文件fd.
注意事项:在修改映射的文件时, 只能在原长度上修改, 不能增加文件长度, 因为内存是已经分配好的
Linux-mmap函数介绍mmap函数是unix/linux下的系统调用,来看《Unix Netword programming》卷二12.2节对mmap的介绍:
The mmap function maps either a file or a Posix shared memory object into the address space of a process. We use this function for three purposes:1. with a regular file to provide memory-mapped I/O 2. with special files to provide anonymous memory mappings 3. with shm_open to provide Posix shared memory between unrelated processes mmap
系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而 Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通
正在阅读:
Linux的mmap文件内存映射机制04-24
高中语文必修4第19课《谏太宗十思疏》导学稿(学生版)03-29
基于Profibus-DP协议现场总线的控制系统设计10-20
13秋《西方经济学》(一)作业404-27
招商人员薪酬和佣金提成激励方案05-11
应用化学专业毕业论文模板(年产4万吨醋酸乙烯戚贺成)10-25
2012单片机原理与应用课程设计大纲03-26
昵称瓶——可口可乐的青春逆袭06-12
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 映射
- 机制
- 内存
- 文件
- Linux
- mmap
- (数学分析教案)第四章
- 六年级奥数第一讲 - 比和比例(学生用)
- 奥数:五年级奥数40讲教案第37讲 简单列举
- 第十三章 紫外可见光谱分析 - 图文
- 武汉市政府批复的《武汉临空经济区总体发展规划》
- 星巴克外部环境分析
- 江苏省盐城市2018年中考英语试题含答案(Word版)
- 公司管理水平提升总结
- 大温差小流量系统空调的研究
- 2009年初中生物复习会考生物模拟试卷(二)
- 《管理学》章节习题2012版
- 中国人民财产保险股份有限公司涞水支公司(企业信用报告)- 天眼
- 有限空间作业应急管理制度
- 第七讲 电路二
- 2017鸡年女宝宝名字:2017女孩取名内涵诗意名字
- 风险和机遇应对措施管理控制程序
- 深圳市事业单位改革文件集、关于推行法定机构试点的意见等
- 黄州区公路段文明创建纪实(已改)
- 新人教版八年级上册英语第七单元测试题附答案
- 职业学校考察报告