Understanding mmap: How Memory Mapping Improves I/O Performance
This article explains how mmap maps files into a process's virtual memory to eliminate double data copies and reduce system‑call overhead, offering performance gains, a simpler programming model, and discusses its limitations such as address‑space constraints and page‑fault latency.
Before discussing the advantages of mmap , we need to understand the performance bottlenecks of traditional read/write I/O, which involve two copies: from disk to the kernel page cache and from the kernel cache to user‑space buffers, consuming CPU, memory and causing costly context switches.
How mmap “bypasses” traditional I/O performance traps
mmap maps a file directly into a process’s virtual address space, turning the I/O problem into a memory‑management problem and eliminating the double‑copy path.
mmap reduces system call count
After a file is mapped, the program can read data with ordinary memory instructions, avoiding repeated read/write system calls and the associated user‑kernel mode switches.
// 传统IO方式读取文件
void read_file_traditional(const char* filename){
int fd = open(filename, O_RDONLY);
// ...
// 循环读取文件内容,每次都需要系统调用
while ((n = read(fd, buf, sizeof(buf))) > 0) {
...
}
}
// mmap方式读取文件
void read_file_mmap(const char* filename){
int fd = open(filename, O_RDONLY);
// ...
// 只需一次mmap系统调用
char* addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
unsigned long sum = 0;
// 直接通过内存访问文件内容,无需系统调用
for (size_t i = 0; i < sb.st_size; i++) {
sum += addr[i];
}
}Using strace on Linux easily shows the difference in system‑call frequency.
mmap simplifies the programming model
Because the file appears as a memory array, searching or processing data becomes as simple as iterating over a buffer.
// 传统IO方式搜索文件内容
void search_file_traditional(const char* filename, const char* pattern){
int fd = open(filename, O_RDONLY);
char buf[4096];
ssize_t n;
// 需要手动管理缓冲区,循环读取文件
while ((n = read(fd, buf, sizeof(buf))) > 0) {
// 在缓冲区中查找模式串
for (ssize_t i = 0; i < n; i++) {
if (strncmp(buf + i, pattern, strlen(pattern)) == 0) {
printf("Found pattern at offset %ld\n", lseek(fd, 0, SEEK_CUR) - n + i);
}
}
}
// ...
}
// mmap方式搜索文件内容
void search_file_mmap(const char* filename, const char* pattern){
int fd = open(filename, O_RDONLY);
struct stat sb;
fstat(fd, &sb);
// 一次映射,直接操作内存
char* addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
// 可以像操作数组一样简单地遍历文件内容
for (size_t i = 0; i < sb.st_size; i++) {
if (strncmp(addr + i, pattern, strlen(pattern)) == 0) {
printf("Found pattern at offset %zu\n", i);
}
}
// ...
}The example demonstrates a dramatic reduction in boiler‑plate code.
mmap avoids data copying
Both the kernel and user space share the same physical pages, so data is copied only once from disk to the kernel, not again to user space, reducing memory usage and CPU load.
mmap considerations and limitations
On 32‑bit processes the address space is limited, making large‑file mappings risky; even on 64‑bit systems, mapping terabyte‑scale files requires careful management. Frequent small writes can cause many page faults and TLB misses, making read/write sometimes faster. Real‑time workloads must tolerate unpredictable page‑fault latency, and high‑concurrency scenarios need explicit synchronization.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.