前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Linux 内核 内存管理】内存管理系统调用 ④ ( 代码示例 | mmap 创建内存映射 | munmap 删除内存映射 )

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

作者头像
韩曙亮
发布2023-03-30 14:31:21
1.4K0
发布2023-03-30 14:31:21
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

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


1、fopen 打开或创建文件

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

代码语言:javascript
复制
    // 打开文件
    fd = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, 00777);

2、lseek 设置文件大小

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

代码语言:javascript
复制
    // 修改文件偏移量 , 将文件的读写位置指向文件头后 , 
    // 再增加 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 指针 , 则说明 内存映射 创建失败 ;

代码语言:javascript
复制
    // 创建文件映射
    // 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 创建的 内存映射 ;

代码语言:javascript
复制
    // 删除文件映射 
    munmap(p_student, sizeof(student) * 10);

二、完整代码示例


代码语言:javascript
复制
#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 文件中 , 执行

代码语言:javascript
复制
gcc mmap_demo_01.c -o mmap_demo_01

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

代码语言:javascript
复制
./mmap_demo_01 file

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

执行结果如下 :

代码语言:javascript
复制
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$ 
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、mmap 创建内存映射代码示例
    • 1、fopen 打开或创建文件
      • 2、lseek 设置文件大小
        • 3、mmap 函数使用
          • 4、munmap 删除内存映射
          • 二、完整代码示例
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档