一.文件映射的定义
文件映射是一种将磁盘上的文件映射到进程的虚拟内存空间的机制。
通过这种方式,进程可以直接通过内存地址来读写文件,而不必通过常规的 read 和 write 等系统调用。
我的理解:所谓的文件映射就是,创建一个文件,然后通过Linux提供的文件映射机制,将这个文件和进程的虚拟内存空间的一块内存绑定起来,然后对这个内存进行读写操作,就是对实际磁盘上文件的读写操作。
文件映射也可称内存映射,通常情况下这是一回事,内存映射包括将文件映射到内存的操作,也包括将匿名内存(不与文件关联的内存)映射到进程的地址空间的操作。
文件映射是内存映射的一种特例。
二.文件映射的查看方法【两种方法】
方法一:使用pmap工具
查看对应进程的文件映射信息
$ pmap -X 12345 #查看指定PID的文件映射信息
12345: ./example
0000555555554000 100K r-x-- example
0000555555673000 4K r---- example
0000555555674000 4K rw--- example
00007ffff7de0000 1360K r-x-- libc-2.31.so
...
mapped: 1448K writeable/private: 8K shared: 0K
- 每行代表一个内存映射区域。
- 地址范围、权限、映射类型、文件路径等信息。
- “mapped” 表示映射的总大小,”writeable/private” 表示可写和私有的大小,”shared” 表示共享的大小。
方法二:cat查看文件映射文件
使用 cat /proc/PID/maps
命令可以查看进程的内存映射情况。
每一行都表示一个内存映射区域,格式如下:
address perms offset dev inode pathname
00400000-0040b000 r-xp 00000000 08:01 1167685 /usr/bin/cat
0060a000-0060b000 r--p 0000a000 08:01 1167685 /usr/bin/cat
0060b000-0060c000 rw-p 0000b000 08:01 1167685 /usr/bin/cat
- address: 映射的虚拟内存地址范围。
- perms: 权限,包括读(r)、写(w)、执行(x)等。
- offset: 文件中映射区域的偏移量。
- dev: 设备号。
- inode: 文件在文件系统中的节点号。
- pathname: 映射的文件路径或匿名映射。
三. 如何在Linux下使用文件映射
现在我们通过一个例子演示了如何使用文件映射将文件映射到内存中,然后通过修改内存中的内容,最后通过解除内存映射来进行演示。
example.c文件
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
const char *file_path = "example.txt";
const size_t file_size = 4096;
int fd = open(file_path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
if (ftruncate(fd, file_size) == -1) {
perror("ftruncate");
close(fd);
exit(EXIT_FAILURE);
}
// Create a memory-mapped region
void *addr = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap");
close(fd);
exit(EXIT_FAILURE);
}
// Now 'addr' points to the beginning of the file in memory
// 现在addr表示文件在进程的内存空间代表区域的起始位置
// Write a message to the memory-mapped file
// 向映射文件写入一句消息。
const char *message = "Hello, Memory Mapping!n";
strncpy(addr, message, strlen(message));
printf("Press Enter to exit...n");
getchar(); // Wait for user to press Enter
// Unmap the memory region 解除文件和内存区域的映射关系
if (munmap(addr, file_size) == -1) {
perror("munmap");
close(fd);
exit(EXIT_FAILURE);
}
// Close the file descriptor
close(fd);
return 0;
}
编译执行:
$ ls
example.c
$ gcc example.c -o example
$ ./example
Press Enter to exit...
查看进程的文件映射信息:
$ ps aux|grep example
codersong 1524542 0.0 0.0 2776 1152 pts/0 S+ 19:23 0:00 ./example
codersong 1524547 0.0 0.0 12188 2432 pts/2 S+ 19:23 0:00 grep --color=auto example
$ pmap -X 1524542
1524542: ./example
地址 Perm 偏移量 设备 Inode Size Rss Pss Pss_Dirty Referenced Anonymous LazyFree ShmemPmdMapped FilePmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked THPeligible Mapping
557b482c3000 r--p 00000000 08:03 7124051 4 4 4 0 4 0 0 0 0 0 0 0 0 0 0 example
557b482c4000 r-xp 00001000 08:03 7124051 4 4 4 0 4 0 0 0 0 0 0 0 0 0 0 example
557b482c5000 r--p 00002000 08:03 7124051 4 4 4 0 4 0 0 0 0 0 0 0 0 0 0 example
557b482c6000 r--p 00002000 08:03 7124051 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 example
557b482c7000 rw-p 00003000 08:03 7124051 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 example
557b48e9e000 rw-p 00000000 00:00 0 132 4 4 4 4 4 0 0 0 0 0 0 0 0 0 [heap]
7f8fe5600000 r--p 00000000 08:03 264612 160 160 7 0 160 0 0 0 0 0 0 0 0 0 0 libc.so.6
7f8fe5628000 r-xp 00028000 08:03 264612 1620 788 24 0 788 0 0 0 0 0 0 0 0 0 0 libc.so.6
7f8fe57bd000 r--p 001bd000 08:03 264612 352 64 1 0 64 0 0 0 0 0 0 0 0 0 0 libc.so.6
7f8fe5815000 r--p 00214000 08:03 264612 16 16 16 16 16 16 0 0 0 0 0 0 0 0 0 libc.so.6
7f8fe5819000 rw-p 00218000 08:03 264612 8 8 8 8 8 8 0 0 0 0 0 0 0 0 0 libc.so.6
7f8fe581b000 rw-p 00000000 00:00 0 52 20 20 20 20 20 0 0 0 0 0 0 0 0 0
7f8fe58f6000 rw-p 00000000 00:00 0 12 8 8 8 8 8 0 0 0 0 0 0 0 0 0
7f8fe5908000 rw-p 00000000 00:00 0 8 4 4 4 4 4 0 0 0 0 0 0 0 0 0
7f8fe590a000 r--p 00000000 08:03 264600 8 8 0 0 8 0 0 0 0 0 0 0 0 0 0 ld-linux-x86-64.so.2
7f8fe590c000 r-xp 00002000 08:03 264600 168 168 7 0 168 0 0 0 0 0 0 0 0 0 0 ld-linux-x86-64.so.2
7f8fe5936000 r--p 0002c000 08:03 264600 44 40 1 0 40 0 0 0 0 0 0 0 0 0 0 ld-linux-x86-64.so.2
7f8fe5941000 rw-s 00000000 08:03 7124052 4 4 4 0 4 0 0 0 0 0 0 0 0 0 0 example.txt
7f8fe5942000 r--p 00037000 08:03 264600 8 8 8 8 8 8 0 0 0 0 0 0 0 0 0 ld-linux-x86-64.so.2
7f8fe5944000 rw-p 00039000 08:03 264600 8 8 8 8 8 8 0 0 0 0 0 0 0 0 0 ld-linux-x86-64.so.2
7ffef93f2000 rw-p 00000000 00:00 0 132 12 12 12 12 12 0 0 0 0 0 0 0 0 0 [stack]
7ffef9485000 r--p 00000000 00:00 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [vvar]
7ffef9489000 r-xp 00000000 00:00 0 8 4 0 0 4 0 0 0 0 0 0 0 0 0 0 [vdso]
ffffffffff600000 --xp 00000000 00:00 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [vsyscall]
==== ==== === ========= ========== ========= ======== ============== ============= ============== =============== ==== ======= ====== ===========
2780 1344 152 96 1344 96 0 0 0 0 0 0 0 0 0 KB
$
$
$ cat /proc/1524542/maps
557b482c3000-557b482c4000 r--p 00000000 08:03 7124051 /home/codersong/zhengshihong/example
557b482c4000-557b482c5000 r-xp 00001000 08:03 7124051 /home/codersong/zhengshihong/example
557b482c5000-557b482c6000 r--p 00002000 08:03 7124051 /home/codersong/zhengshihong/example
557b482c6000-557b482c7000 r--p 00002000 08:03 7124051 /home/codersong/zhengshihong/example
557b482c7000-557b482c8000 rw-p 00003000 08:03 7124051 /home/codersong/zhengshihong/example
557b48e9e000-557b48ebf000 rw-p 00000000 00:00 0 [heap]
7f8fe5600000-7f8fe5628000 r--p 00000000 08:03 264612 /usr/lib/x86_64-linux-gnu/libc.so.6
7f8fe5628000-7f8fe57bd000 r-xp 00028000 08:03 264612 /usr/lib/x86_64-linux-gnu/libc.so.6
7f8fe57bd000-7f8fe5815000 r--p 001bd000 08:03 264612 /usr/lib/x86_64-linux-gnu/libc.so.6
7f8fe5815000-7f8fe5819000 r--p 00214000 08:03 264612 /usr/lib/x86_64-linux-gnu/libc.so.6
7f8fe5819000-7f8fe581b000 rw-p 00218000 08:03 264612 /usr/lib/x86_64-linux-gnu/libc.so.6
7f8fe581b000-7f8fe5828000 rw-p 00000000 00:00 0
7f8fe58f6000-7f8fe58f9000 rw-p 00000000 00:00 0
7f8fe5908000-7f8fe590a000 rw-p 00000000 00:00 0
7f8fe590a000-7f8fe590c000 r--p 00000000 08:03 264600 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f8fe590c000-7f8fe5936000 r-xp 00002000 08:03 264600 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f8fe5936000-7f8fe5941000 r--p 0002c000 08:03 264600 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f8fe5941000-7f8fe5942000 rw-s 00000000 08:03 7124052 /home/byzoro/zhengshihong/example.txt
7f8fe5942000-7f8fe5944000 r--p 00037000 08:03 264600 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f8fe5944000-7f8fe5946000 rw-p 00039000 08:03 264600 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ffef93f2000-7ffef9413000 rw-p 00000000 00:00 0 [stack]
7ffef9485000-7ffef9489000 r--p 00000000 00:00 0 [vvar]
7ffef9489000-7ffef948b000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
现在按ctrl+C
退出example程序,查看example.txt文件的内容:
$ cat example.txt
Hello, Memory Mapping!