0%

Linux内存管理mmap分配内存默认对齐

Linux内存管理mmap分配内存默认对齐

使用mmap建立内存映射:

头文件:

1
2
#include <unistd.h> 
#include <sys/mman.h>

定义:

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize);

prot:

  • PROT_EXEC 映射区域可被执行;
  • PROT_READ 映射区域可被读取;
  • PROT_WRITE 映射区域可被写入;
  • PROT_NONE 映射区域不能存取。

flags:

  • MAP_FIXED 如果参数 start 所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
  • MAP_SHARED 对应射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
  • MAP_PRIVATE 对应射区域的写入操作会产生一个映射文件的复制,即私人的”写入时复制” (copy on write)对此区域作的任何修改都不会写回原来的文件内容。
  • MAP_ANONYMOUS 建立匿名映射,此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
  • MAP_DENYWRITE 只允许对应射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
  • MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。

在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。

错误代码:

  • EBADF 参数fd 不是有效的文件描述词。
  • EACCES 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED 则要有PROT_WRITE 以及该文件要能写入。
  • EINVAL 参数start、length 或offset 有一个不合法。
  • EAGAIN 文件被锁住,或是有太多内存被锁住。
  • ENOMEM 内存不足。

不使用MAP_FIXED,即使指定非页对齐的start, 也会分配页对齐的地址. 如果此时使用MAP_FIXED, 则会返回错误.

举例:

1
2
void *p = mmap(0x20001000, 10240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); //在0x20001000处分配1024*10个B空间
void *p = mmap(0x20000012, 10240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); // 会返回错误
tips:

0x20000012中每个数字表示4bit, 3个数就是12bit也就是2^12次方,即4k大小. 所以0x20001000不会报错,但是0x20000012会,因为地址不是一个整页的起始地址. 如果移除了MAP_FIXED就不会, 但是实际分配的地址起始会变成0x20000000

使用场景是:分配内存、读写大文件、连接动态库文件、多进程间共享内存