mmap 匿名文件映射的主要作用是返回一段指定大小的虚拟地址空间。
1. mmap 匿名映射的核心作用
当使用mmap
进行匿名映射时(即不关联实际文件,通过MAP_ANONYMOUS
标志创建),操作系统会:
- 在进程的虚拟地址空间中分配一段连续的区域
- 将这段地址空间映射到物理内存(按需分配,可能延迟分配)
- 返回指向该虚拟地址空间起始位置的指针
这个过程类似于调用malloc
分配内存,但有几个重要区别:
特性 | mmap 匿名映射 | malloc |
---|---|---|
底层实现 | 直接调用内存映射机制 | 基于 brk 或 mmap(大块内存) |
分配粒度 | 按页分配(通常 4KB 或更大) | 按请求大小分配(更灵活) |
释放方式 | 必须显式调用 munmap | 自动管理(free) |
内存连续性 | 保证虚拟地址连续 | 虚拟地址连续 |
初始内容 | 全零 | 可能包含垃圾数据(需初始化) |
适用场景 | 大内存块、跨进程共享 | 中小内存块、频繁分配释放 |
2. 典型应用场景
- 大内存块分配:当需要分配超过 128KB 的内存时,mmap 通常比 malloc 更高效(避免内存碎片)
- 进程间共享内存:结合
MAP_SHARED
标志,多个进程可访问同一块物理内存 - 延迟分配优化:利用 Linux 的 "请求调页" 机制,实际物理内存仅在访问时分配
- 内存映射文件替代:当不需要持久化存储时,匿名映射比文件映射更简洁
3. 示例代码
以下是使用 mmap 创建匿名映射的基本示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
int main() {
size_t size = 1024 * 1024; // 1MB
void *ptr = mmap(
NULL, // 让系统选择地址
size, // 映射大小
PROT_READ | PROT_WRITE, // 可读可写
MAP_ANONYMOUS | MAP_PRIVATE, // 匿名私有映射
-1, // 不关联文件
0 // 偏移量
);
if (ptr == MAP_FAILED) {
perror("mmap failed");
return 1;
}
// 使用内存
for (int i = 0; i < 1024; i++) {
((char*)ptr)[i] = 'A';
}
// 释放内存
if (munmap(ptr, size) == -1) {
perror("munmap failed");
return 1;
}
return 0;
}
4. 关键特性说明
- 虚拟地址保证:mmap 返回的地址空间是连续的虚拟地址,但物理内存可能不连续(通过页表映射实现)
- 零初始化:匿名映射的内存默认初始化为零(不同于 malloc)
- 内存释放:必须显式调用 munmap 释放,否则会导致内存泄漏
- 权限控制:通过
PROT_*
标志可精确控制内存访问权限(如只读、可执行等)
5.用户空间与 GPU 内存的映射
GPU 驱动需要将物理显存(VRAM)或系统内存映射到用户空间,使应用程序能够直接访问:
- 零拷贝数据传输:通过
MAP_SHARED
标志,用户空间缓冲区可直接被 GPU 访问,避免数据在用户空间和内核空间之间的复制 - 显存管理:将 VRAM 区域映射到用户空间,实现高效的图形数据读写
这种机制为高性能应用提供了灵活且高效的内存管理方式,尤其适合需要大块连续内存或跨进程数据共享的场景。