mmap/munmap 函数

更多Linux内核驱动开发教程,《Linux内核编程》1~12期,请点击:王利涛老师个人淘宝店:Linux内核编程

在用户空间申请内存,当申请的内存比较大时,再使用malloc系函数,数据拷贝开销比较大,这时候我们可以采用mmap函数,
将一段虚拟地址空间直接映射到物理内存,这样,当我们在用户空间和内核空间传输数据时,就省去了数据拷贝这个过程了,
而是直接操作物理内存。
mmap和munmap对应的函数原型如下:

#include <sys/mman.h>

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

其中参数 addr表示要映射的虚拟空间起始地址,length表示要映射的长度。如果addr为NULL,那么系统会自动分配一段空闲的虚拟地址空间。

prot 表示要映射的内存保护表示,常见的参数有:

  • PROT_EXEC :页内容可以被执行
  • PROT_READ :页内容可以被读取
  • PROT_WRITE :页可以被写入
  • PROT_NONE :页不可访问
    以上内存保护标识,可以单独作为一个参数,也可以几个标识结合在一起构成一个组合参数,比如 PROT_EXEC | PROT_READ

flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体:

  • MAP_FIXED :使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
  • MAP_SHARED :与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
  • MAP_PRIVATE :建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
  • MAP_DENYWRITE :这个标志被忽略。
  • MAP_EXECUTABLE :同上
  • 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一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。

mmap分为匿名映射和文件映射。如果是文件映射的话,参数fd表示要映射的文件句柄,offset表示偏移。如果是匿名映射的话,这个参数一般设置为-1

驱动开发核心理论,Linux内核开发入门实战视频教程:《Linux内核编程》,具有一线芯片原厂开发经验的驱动工程师录制,详情点击:王利涛老师个人淘宝店:Linux内核编程