【Linux 内核 内存管理】内存管理系统调用 ④ ( 代码示例 | mmap 创建内存映射 | munmap 删除内存映射 )

网友投稿 738 2022-05-29

文章目录

一、mmap 创建内存映射代码示例

1、fopen 打开或创建文件

2、lseek 设置文件大小

3、mmap 函数使用

4、munmap 删除内存映射

二、完整代码示例

一、mmap 创建内存映射代码示例

1、fopen 打开或创建文件

使用 fopen 函数 , 打开一个文件 , 此时文件可能不存在 , 需要创建文件 ;

// 打开文件 fd = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, 00777);

2、lseek 设置文件大小

通过 lseek 函数 , 设置文件的大小 , 将文件偏移 sizeof(student) * 10 - 1 大小 , 就是设置文件大小设置为 10 个 student 结构体大小

// 修改文件偏移量 , 将文件的读写位置指向文件头后 , // 再增加 sizeof(student) * 10 - 1 偏移量 , 偏移量从 0 开始计算 , // 该操作的作用是将文件大小设置为 10 个 student 结构体大小 lseek(fd, sizeof(student) * 10 - 1, SEEK_SET);

3、mmap 函数使用

调用 mmap 函数 , 创建文件映射 , 相关参数作用如下 :

NULL : 映射区的开始地址

sizeof(student) * 1 : 文件映射区的长度

PROT_READ | PROT_WRITE : 内存保护的标志位 , 该内存页的内容可以 读取 写入

MAP_SHARED : 指定映射关系 , 指的是该映射是进程的共享内存空间

fd : 文件描述符 , 被映射的文件

0 : 被映射文件的偏移量 , 从文件的哪个字节位置开始映射

如果返回 -1 指针 , 则说明 内存映射 创建失败 ;

// 创建文件映射 // NULL : 映射区的开始地址 // sizeof(student) * 1 : 文件映射区的长度 // PROT_READ | PROT_WRITE : 内存保护的标志位 , 该内存页的内容可以 读取 写入 // MAP_SHARED : 指定映射关系 , 指的是该映射是进程的共享内存空间 // fd : 文件描述符 , 被映射的文件 // 0 : 被映射文件的偏移量 , 从文件的哪个字节位置开始映射 p_student = (student*)mmap(NULL, sizeof(student) * 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // mmap 文件映射创建失败 if (p_student == (void*) - 1) { printf("mmap 文件映射创建失败 !"); return -1; } // 创建完文件映射之后 , 文件描述符就可以释放了 close(fd);

4、munmap 删除内存映射

调用 munmap 函数 , 删除 mmap 创建的 内存映射 ;

// 删除文件映射 munmap(p_student, sizeof(student) * 10);

二、完整代码示例

#include #include #include #include #include #include #include /* 定义一个结构体 代表 " 学生 " 结构体成员中设置一个 char* 字符串 和 int 类型数据 分别代表 学生的 姓名 和 年龄 */ typedef struct { char name[4]; // 姓名 int age; // 年龄 }student; int main(int argc, char** argv) { // 打开文件的 文件描述符 int fd; // 循环控制变量 int i; // 学生结构体指针 , 指向 student 结构体类型变量 student* p_student; // 用于生成姓名字符串 char name_char; // 打开文件 fd = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, 00777); // 修改文件偏移量 , 将文件的读写位置指向文件头后 , // 再增加 sizeof(student) * 10 - 1 偏移量 , 偏移量从 0 开始计算 , // 该操作的作用是将文件大小设置为 10 个 student 结构体大小 lseek(fd, sizeof(student) * 10 - 1, SEEK_SET); // 向文件中写入数据 , 生成文件 write(fd, "", 1); // 创建文件映射 // NULL : 映射区的开始地址 // sizeof(student) * 1 : 文件映射区的长度 // PROT_READ | PROT_WRITE : 内存保护的标志位 , 该内存页的内容可以 读取 写入 // MAP_SHARED : 指定映射关系 , 指的是该映射是进程的共享内存空间 // fd : 文件描述符 , 被映射的文件 // 0 : 被映射文件的偏移量 , 从文件的哪个字节位置开始映射 p_student = (student*)mmap(NULL, sizeof(student) * 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // mmap 文件映射创建失败 if (p_student == (void*) - 1) { printf("mmap 文件映射创建失败 !"); return -1; } // 创建完文件映射之后 , 文件描述符就可以释放了 close(fd); // 逐个字节拷贝 name_char = 'A'; for (i = 0; i < 10; i++) { // 将字符串的第 1 个字节设置为 '

#include #include #include #include #include #include #include /* 定义一个结构体 代表 " 学生 " 结构体成员中设置一个 char* 字符串 和 int 类型数据 分别代表 学生的 姓名 和 年龄 */ typedef struct { char name[4]; // 姓名 int age; // 年龄 }student; int main(int argc, char** argv) { // 打开文件的 文件描述符 int fd; // 循环控制变量 int i; // 学生结构体指针 , 指向 student 结构体类型变量 student* p_student; // 用于生成姓名字符串 char name_char; // 打开文件 fd = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, 00777); // 修改文件偏移量 , 将文件的读写位置指向文件头后 , // 再增加 sizeof(student) * 10 - 1 偏移量 , 偏移量从 0 开始计算 , // 该操作的作用是将文件大小设置为 10 个 student 结构体大小 lseek(fd, sizeof(student) * 10 - 1, SEEK_SET); // 向文件中写入数据 , 生成文件 write(fd, "", 1); // 创建文件映射 // NULL : 映射区的开始地址 // sizeof(student) * 1 : 文件映射区的长度 // PROT_READ | PROT_WRITE : 内存保护的标志位 , 该内存页的内容可以 读取 写入 // MAP_SHARED : 指定映射关系 , 指的是该映射是进程的共享内存空间 // fd : 文件描述符 , 被映射的文件 // 0 : 被映射文件的偏移量 , 从文件的哪个字节位置开始映射 p_student = (student*)mmap(NULL, sizeof(student) * 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // mmap 文件映射创建失败 if (p_student == (void*) - 1) { printf("mmap 文件映射创建失败 !"); return -1; } // 创建完文件映射之后 , 文件描述符就可以释放了 close(fd); // 逐个字节拷贝 name_char = 'A'; for (i = 0; i < 10; i++) { // 将字符串的第 1 个字节设置为 '\0' , 这是 字符串的结尾 , // 第 0 个字节就是字符串的实际内容 , 该字符串只有 1 个字符 (*(p_student + i)).name[1] = '\0'; // 拷贝 字符串 到 p_student 指向的内存中 , 该内存是文件映射内存 // 拷贝内存的同时 , 也会修改文件内容 memcpy((*(p_student + i)).name, &name_char, 1); // 设置 (*(p_student + i)).age = 1 + i; // 生成不同的字符 , 用于生成不同的 name 字符串 name_char++; } printf("文件初始化完毕 !\n"); // 休眠 8 秒 sleep(8); // 删除文件映射 munmap(p_student, sizeof(student) * 10); printf("mmap 文件映射展示完毕 !\n"); return 0; }

' , 这是 字符串的结尾 , // 第 0 个字节就是字符串的实际内容 , 该字符串只有 1 个字符 (*(p_student + i)).name[1] = '

#include #include #include #include #include #include #include /* 定义一个结构体 代表 " 学生 " 结构体成员中设置一个 char* 字符串 和 int 类型数据 分别代表 学生的 姓名 和 年龄 */ typedef struct { char name[4]; // 姓名 int age; // 年龄 }student; int main(int argc, char** argv) { // 打开文件的 文件描述符 int fd; // 循环控制变量 int i; // 学生结构体指针 , 指向 student 结构体类型变量 student* p_student; // 用于生成姓名字符串 char name_char; // 打开文件 fd = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, 00777); // 修改文件偏移量 , 将文件的读写位置指向文件头后 , // 再增加 sizeof(student) * 10 - 1 偏移量 , 偏移量从 0 开始计算 , // 该操作的作用是将文件大小设置为 10 个 student 结构体大小 lseek(fd, sizeof(student) * 10 - 1, SEEK_SET); // 向文件中写入数据 , 生成文件 write(fd, "", 1); // 创建文件映射 // NULL : 映射区的开始地址 // sizeof(student) * 1 : 文件映射区的长度 // PROT_READ | PROT_WRITE : 内存保护的标志位 , 该内存页的内容可以 读取 写入 // MAP_SHARED : 指定映射关系 , 指的是该映射是进程的共享内存空间 // fd : 文件描述符 , 被映射的文件 // 0 : 被映射文件的偏移量 , 从文件的哪个字节位置开始映射 p_student = (student*)mmap(NULL, sizeof(student) * 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // mmap 文件映射创建失败 if (p_student == (void*) - 1) { printf("mmap 文件映射创建失败 !"); return -1; } // 创建完文件映射之后 , 文件描述符就可以释放了 close(fd); // 逐个字节拷贝 name_char = 'A'; for (i = 0; i < 10; i++) { // 将字符串的第 1 个字节设置为 '\0' , 这是 字符串的结尾 , // 第 0 个字节就是字符串的实际内容 , 该字符串只有 1 个字符 (*(p_student + i)).name[1] = '\0'; // 拷贝 字符串 到 p_student 指向的内存中 , 该内存是文件映射内存 // 拷贝内存的同时 , 也会修改文件内容 memcpy((*(p_student + i)).name, &name_char, 1); // 设置 (*(p_student + i)).age = 1 + i; // 生成不同的字符 , 用于生成不同的 name 字符串 name_char++; } printf("文件初始化完毕 !\n"); // 休眠 8 秒 sleep(8); // 删除文件映射 munmap(p_student, sizeof(student) * 10); printf("mmap 文件映射展示完毕 !\n"); return 0; }

'; // 拷贝 字符串 到 p_student 指向的内存中 , 该内存是文件映射内存 // 拷贝内存的同时 , 也会修改文件内容 memcpy((*(p_student + i)).name, &name_char, 1); // 设置 (*(p_student + i)).age = 1 + i; // 生成不同的字符 , 用于生成不同的 name 字符串 name_char++; } printf("文件初始化完毕 !\n"); // 休眠 8 秒 sleep(8); // 删除文件映射 munmap(p_student, sizeof(student) * 10); printf("mmap 文件映射展示完毕 !\n"); return 0; }

编译并执行代码 : 上述源码保存在 mmap_demo_01.c 文件中 , 执行

gcc mmap_demo_01.c -o mmap_demo_01

命令 , 编译上述源码 , 并输出可执行文件 mmap_demo_01 , 执行

./mmap_demo_01 file

命令 , 开始执行该应用程序 ;

执行结果如下 :

【Linux 内核 内存管理】内存管理系统调用 ④ ( 代码示例 | mmap 创建内存映射 | munmap 删除内存映射 )

han@ubuntu:~/vscode/mmap$ gcc mmap_demo_01.c -o mmap_demo_01 han@ubuntu:~/vscode/mmap$ ./mmap_demo_01 file 文件初始化完毕 ! mmap 文件映射展示完毕 ! han@ubuntu:~/vscode/mmap$

Linux 项目管理 ProjectMan

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:ICT【计算机网络】学习笔记一
下一篇:你还在 Docker 中跑 MySQL?恭喜你,可以下岗了!
相关文章