Linux 内核 内存管理内存管理系统调用 ④ ( 代码示例 | mmap 创建内存映射 | munmap 删除内存映射 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 内核 内存管理内存管理系统调用 ④ ( 代码示例 | mmap 创建内存映射 | 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 <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
/*
定义一个结构体 代表 " 学生 "
结构体成员中设置一个 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;
编译并执行代码 : 上述源码保存在 mmap_demo_01.c 文件中 , 执行
gcc mmap_demo_01.c -o mmap_demo_01
命令 , 编译上述源码 , 并输出可执行文件 mmap_demo_01 , 执行
./mmap_demo_01 file
命令 , 开始执行该应用程序 ;
执行结果如下 :
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 内核 内存管理内存管理系统调用 ④ ( 代码示例 | mmap 创建内存映射 | munmap 删除内存映射 )的主要内容,如果未能解决你的问题,请参考以下文章
Linux 内核 内存管理mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )
Linux 内核 内存管理内存管理系统调用 ⑤ ( 代码示例 | 多进程共享 mmap 内存映射示例 )
Linux 内核 内存管理分区伙伴分配器 ④ ( 备用内存区域列表排序方式 | 节点优先顺序 | 区域优先顺序 | 排序方式优缺点 | 默认排序方式 )
Linux 内核 内存管理Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )
Linux 内核 内存管理Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )
Linux 内核 内存管理物理内存组织结构 ④ ( 内存区域 zone 简介 | zone 结构体源码分析 | zone 结构体源码 )