mmap原理
- open一个文件,然后调用mmap系统调用,将文件的内容的全部或一部分直接映射到进程虚拟空间中文件存储映射部分;
- 完成映射关系后,mmap返回值是一个指针,进程可以通过采用指针方式读写操作这一段内存;
- 但mmap并不分配物理地址空间,只是占有了进程的虚拟地址空间,当多个进程需要同时访问这个文件的时候,每个进程都将文件所存储的内核缓冲区映射到自己的进程空间虚拟地址中。
- 当第一个进程访问内核缓冲区的时候,由于没有实际拷贝数据,这时候MMU(内存管理单元)在地址映射表中找不到与该虚拟内存空间相对应的物理地址,此时会触发缺页中断;
- 缺页中断后,内核会将文件的这一页数据读入到内核缓冲区中,并更新进程的页表,使得页表指向内核缓冲区这一页,之后有其他的进程再次访问这一页的时候,该页已经在内存中了
当CPU读取数据时,是由内存管理单元(MMU)管理的。MMU位于CPU与物理内存之间,它包含从虚地址向物理内存地址转化的映射信息。当CPU引用一个内存位置时,MMU决定哪些页需要驻留(通常通过移位或屏蔽地址的某些位)以及转化虚拟页号到物理页号。
当某个进程读取磁盘上的数据时,进程要求其缓冲通过read()系统调用填满,这个系统调用导致内核想磁盘控制硬件发出一条命令要从磁盘获取数据。磁盘控制器通过DMA直接将数据写入内核的内存缓冲区,不需要CPU协助。当请求read()操作时,一旦磁盘控制器完成了缓存的填写,内核从内核空间的临时缓存拷贝数据到进程指定的缓存中。
用户空间是常规进程所在的区域,该区域执行的代码不能直接访问硬件设备。内核空间是操作系统所在的区域,该区域可以与设备控制器通讯,控制用户区域进程的运行状态。
内存映射文件技术是操作系统提供的一种新的文件数据存取机制,利用内存映射文件技术,系统可以在内存空间中为文件保留一部分空间,并将文件映射到这块保留空间,一旦文件被映射后,操作系统将管理页映射缓冲以及高速缓冲等任务,而不需要调用分配、释放内存块和文件输入/输出的API函数,也不需要自己提供任何缓冲算法。
使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O 操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
以上就是Android中对APP深度优化,重要的内存映射机制(mmap)的介绍学习,APP的深度优化还有很多还要掌握的,更多内容在《Android性能优化解析》里面包含了7个优化板块,比喻:卡顿优化、UI优化、启动优化等等优化学习。
函数原型
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
start:映射区的开始地址,设置0时表示由系统决定映射区的起始地址。
length:映射区的长度。//长度单位是以字节为单位,不足一内存页按一内存页处理
prot:期望的内存保护标志,不能与文件的打开模式冲突
PROT_EXEC //页内容可以被执行
PROT_READ //页内容可以被读取
PROT_WRITE //页可以被写入
PROT_NONE //页不可访问
flags:指定映射对象的类型,映射选项和映射页是否可以共享。
MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者[munmap](https://baike.baidu.com/item/munmap)()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时[内存不足],对映射区的修改会引起段违例信号。
MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
MAP_GROWSDOWN //用于堆栈,告诉[内核]VM系统,映射区可以向下扩展。
MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
MAP_FILE //兼容标志,被忽略。
MAP_32BIT //将映射区放在进程[地址空间]的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立[页表]入口。
fd:有效的文件描述符。一般是由[open]()函数返回,其值也可以设置为-1,此时需要指定flags参数中的MAP_ANON,表明进行的是匿名映射。
offset:被映射对象内容的起点。