【Linux内核】内存映射原理

news2024/11/25 7:50:50

【Linux内核】内存映射原理

物理地址空间

  1. 物理地址是处理器在总线上能看到的地址,使用RISC(Reduced Instruction Set Computing精简指令集)的处理器通常只实现一个物理地址空间,外围设备和物理内存使用统一的物理空间,

    有些架构的处理器把分配给外围设备的物理地址称为设备内存

    处理器通过外围设备控制器里面的寄存器来访问外围设备,寄存器分为控制寄存器,状态寄存器和数据寄存器

    外围设备的寄存器通常被常备连续的编址,处理器对外围设备寄存器的编址方式分为两种:I/O映射方式,内存映射方式

    • IO映射方式:x86处理器专门为外围设备单独提供一个空间,通过单独的指令(如in out)来访问这个空间的地址
    • 内存映射方式:外围设备和物理内存使用同一个物理空间,处理器以相同方式访问物理内存和外围设备,那么应用如何访问外围设备呢? 操作系统提供单独的函数将外围设备对应的地址映射到应用的虚拟内存中,从而使应用能访问设备

    ARM64架构分为两种内存类型:

    • 正常内存(Normal Memory) :包括物理内存和只读存在器(ROM) ;

      对于正常内存来讲可以设置共享属性,包括缓冲区的共享属性,共享属性分为不可共享,内部共享和外部共享.不可共享:制备处理器一个核心使用,内部共享:可以被多个核使用,外部共享:可以被DMI(DMI是指Direct Media InterfaceI(直接媒体接口))等共享1

    • 设备内存(Device Memory)∶指分配给外围设备寄存器的物理地址区域

      设备内存的共享属性总是外部共享

内存映射原理

​ 创建内存映射时,在进程的用户虚拟地址空间中分配一个虚拟内存区域,内核采用一个延迟物理内存分配策略,在进程第一次访问虚拟页的时候产生缺页异常2

​ 如果是文件映射,那么分配物理页把文件指定的区域数据读到物理页当中,然后把应用的虚拟页表映射到物理页,

​ 如果是匿名映射,就分配物理页,让后把虚拟页映射到物理页

内存映射即在进程的虚拟地址空间创建一个映射,分为两种:

  • 文件映射:文件支持内存映射,把文件的一段区域映射进程的虚拟空间,文件源式存储设备上的文件

    两个进程可以使用共享的文件映射实现共享内存

  • 匿名映射3:没有文件支持的映射,把物理内存映射到进程里的虚拟空间,无数据源

    匿名映射通常是私有映射,只可能出现在父进程和子进程之间

在进程的虚拟地址空间中,代码段和数据段是私有文件映射

未初始化的数据段,堆栈是私有的匿名映射

线程启动映射过程,并且在虚拟地址空间中为内存映射创建一个映射区,先在用户空间调用mmap函数,并且在内存虚拟空间中找到一段连续空闲的符合要求的虚拟地址,对这个区域初始化,并插入进程虚拟空间地址的链表,让后再内核中系统调用,实现文件的物理地址和进程虚拟地址之间一一对应的关系,进程开始查询文件内容,这是虽然进程虚拟内存与文件物理地址已经建立映射关系,但由于文件相关区域还没有加载到物理内存中,这是就会引发缺页中断,请求将磁盘内容调入内存当中,先在进程缓存空间swapcathe4中进行查找,如果没有找到,就通过nopage()把缺页从磁盘调入内存,如果你对内存进行写入改变内存内容,一段时间后,系统就会将改变的脏页写入硬盘,也可以使用函数强制及时同步.

数据结构

struct vm_area_struct {
	/* The first cache line has the info for VMA tree walking. */

	unsigned long vm_start;		/* Our start address within vm_mm. */
	unsigned long vm_end;		/* The first byte after our end address
					   within vm_mm. */

	/* linked list of VM areas per task, sorted by address */
	struct vm_area_struct *vm_next, *vm_prev;//虚拟内存连接
//红黑树实现
	struct rb_node vm_rb;

	/*
	 * Largest free memory gap in bytes to the left of this VMA.
	 * Either between this VMA and vma->vm_prev, or between one of the
	 * VMAs below us in the VMA rbtree and its ->vm_prev. This helps
	 * get_unmapped_area find a free area of the right size.
	 */
	unsigned long rb_subtree_gap;

	/* Second cache line starts here. */

	struct mm_struct *vm_mm;//指向内存描述符,虚拟内存区域所属的用户虚拟空间	/* The address space we belong to. */
	pgprot_t vm_page_prot;	//权限呗	/* Access permissions of this VMA. */
	unsigned long vm_flags;		/* Flags, see mm.h. */
}
struct vm_operations_struct {
    //虚拟内存操作集合
	void (*open)(struct vm_area_struct * area);//创建虚拟内存区域
	void (*close)(struct vm_area_struct * area);//关闭虚拟内存区域
	int (*mremap)(struct vm_area_struct * area);//移动虚拟内存区域是调用
	int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);//缺页异常处理,将文件加载到内存中
	int (*pmd_fault)(struct vm_area_struct *, unsigned long address,
						pmd_t *, unsigned int flags);
	void (*map_pages)(struct vm_area_struct *vma, struct vm_fault *vmf);

	/* notification that a previously read-only page is about to become
	 * writable, if an error is returned it will cause a SIGBUS */
	int (*page_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf);

	/* same as page_mkwrite when using VM_PFNMAP|VM_MIXEDMAP */
	int (*pfn_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf);
}

image-20210909224459409

系统调用

​ 应用程序通常使用C标准库提供的函数malloc()申请内存,glibc库的内存分配器ptmalloc使用brk或mmap向内核以页为单位申请虚拟内存然后把页划分为小块共应用程序使用

​ 应用程序可以使用mmap向内核申请虚拟内存

1、mmap()----创建内存映射

#include <sys/mman.h> 

void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset);

系统调用mmap():进程创建匿名的内存映射,把内存的物理页映射到进程的虚拟地址空间。进程把文件映射到进程的虚拟地址空间,可以像访问内存一样访问文件,不需要调用系统调用read()/write()访问文件,从而避免用户模式和内核模式之间的切换,提高读写文件速度。 两个进程针对同一个文件创建共享的内存映射,实现共享内存。

2、munmap()----删除内存映射

#include <sys/mman.h> 

int munmap(void *addr, size_t len); 

3、mprotect()----设置虚拟内存区域的访问权限

#include <sys/mman.h> 

int mprotect(void *addr, size_t len, int prot);

1、进程启动映射过程,并且在虚拟地址空间中为映射创建虚拟映射区域;
2、调用内核空间的系统调用函数mmap(不同于用户空间函数),实现文件物理地址和进程虚拟的一一映射关系;
3、进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝。

上代码:

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct
{
    /* data */
    char name[4];
    int age;
} people;

void main(int argc, char **argv)
{
    int fd, i;
    people *p_map;
    char temp;
    fd = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, 00777);

    lseek(fd, sizeof(people) * 5 - 1, SEEK_SET);
    write(fd, "", 1);

    p_map = (people *)mmap(NULL, sizeof(people) * 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (p_map == (void *)-1)
    {
        fprintf(stderr, "mmap : %s \n", strerror(errno));
        return;
    }
    close(fd);

    temp = 'A';
    for (i = 0; i < 10; i++)
    {
        temp = temp + 1;
        (*(p_map + i)).name[1] = '\0';
        memcpy((*(p_map + i)).name, &temp, 1);
        (*(p_map + i)).age = 30 + i;
    }

    printf("Initialize.\n");

    sleep(15);

    munmap(p_map, sizeof(people) * 10);

    printf("UMA OK.\n");
}

#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

typedef struct 
{
    /* data */
    char name[4];
    int age;
}people;

void main(int argc,char**argv)
{
    int fd,i;
    people *p_map;

    fd=open(argv[1],O_CREAT|O_RDWR,00777);
    p_map=(people*)mmap(NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    if(p_map==(void*)-1)
    {
        fprintf(stderr,"mmap : %s \n",strerror(errno));
        return ;
    }

    for(i=0;i<10;i++)
    {
        printf("name:%s age:%d\n",(*(p_map+i)).name,(*(p_map+i)).age);
    }

    munmap(p_map,sizeof(people)*10);   

}




  1. DMI是Intel(英特尔)公司开发用于连接主板南北桥的总线,取代了以前的Hub-Link总线。DMI采用点对点的连接方式,时钟频率为100MHz,由于它是基于PCI-Express总线,因此具有PCI-E总线的优势。DMI实现了上行与下行各1GB/s的数据传输率,总带宽达到2GB/s,这个高速接口集成了高级优先服务,允许并发通讯和真正的同步传输能力。它的基本功能对于软件是完全透明的,因此早期的软件也可以正常操作。 ↩︎

  2. 缺页异常,页缺失Page fault,指的是硬错误、硬中断、分页错误、寻页缺失、缺页中断、页故障等)指的是当软件试图访问已映射在虚拟地址空间中,但是目前并未被加载在物理内存中的一个分页时,由中央处理器的内存管理单元所发出的中断。通常情况下,用于处理此中断的程序是操作系统的一部分。如果操作系统判断此次访问是有效的,那么操作系统会尝试将相关的分页从硬盘上的虚拟内存文件中调入内存。而如果访问是不被允许的,那么操作系统通常会结束相关的进程。虽然其名为“页缺失”错误,但实际上这并不一定是一种错误。而且这一机制对于利用虚拟内存来增加程序可用内存空间的操作系统(比如Microsoft Windows和各种类 Unix 系统)中都是常见且有必要的。 ↩︎

  3. mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。进程在用户空间调用库函数mmap,原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);来实现内存映射。从原型可知,存在一个参数为fd,根据fd,存在一种情况叫匿名映射,所谓匿名映射,表示不存在fd这么个真实的文件。实现匿名映射的方式主要有以下两种: 1、BSD 提供匿名映射的办法是fd =-1,同时 flag 指定为MAP_SHARE|MAP_ANON。 ptr = mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON,-1,0);2、SVR4 提供匿名映射的办法是 open /dev/zero设备文件,把返回的文件描述符,作为mmap的fd参数。 fd = open(“/dev/zero”,O_RDWR); /dev/zero 是一个特殊的文件,当你读它的时候,它会提供无限的空字符(NULL, ASCII NUL, 0x00) 一个作用是用它作为源,产生一个特定大小的空白文件。匿名内存映射适用于具有亲属关系的进程之间;由于父子进程之间的这种特殊的父子关系,在父进程中先调用mmap(),然后调用fork(),那么,在调用fork() 之后,子进程继承了父进程的所有资源,当然也包括匿名映射后的地址空间和mmap()返回的地址,这样父子进程就可以通过映射区域进行通信了;这里不是一般的继承关系,一般来说,子进程单独维护从父进程继承下来的一些变量,而mmap()返回的地址却是由父子进程共同维护的;对于具有亲属关系的进程之间实现共享内存的最好方式应该是采用匿名映射的方式。此时,不必指定具体的条件,只要设置相应的标志即可。 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1101539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于matlab/simulink永磁直驱风力发电低电压穿越控制仿真模型

很久没更新了&#xff0c;下面继续更新电能质量治理这块的内容&#xff0c;今天分享的直驱式风力发电LVRT控制。 随着风力发电规模不断扩大&#xff0c;风电在电网系统中所占份额逐渐增加。当风电并网运行时&#xff0c;会发生很多种并网问题&#xff0c;其中最常见的问题之一就…

macos 12 支持机型 macOS Monterey 更新中新增的功能

macOS Monterey 能让你以全然一新的方式与他人沟通联络、共享内容和挥洒创意。尽享 FaceTime 通话新增的音频和视频增强功能&#xff0c;包括空间音频和人像模式。通过功能强大的效率类工具&#xff08;例如专注模式、快速备忘录和 Safari 浏览器中的标签页组&#xff09;完成更…

软件产品质量如何保障?找对软件测试公司是关键

软件产品的质量对于企业来说至关重要&#xff0c;它直接关系到用户的满意度和企业的声誉。然而&#xff0c;由于软件开发的复杂性和多样性&#xff0c;确保软件产品质量成为一项挑战。为了解决这一问题&#xff0c;找对合适的软件测试公司是至关重要的。 软件测试公司具备丰富…

考试成绩怎么查?

如何创建一个学生自助查询考试成绩的系统&#xff1f;还包括一个网页界面&#xff1f;能够让学生们通过多种方式轻松查询他们的成绩&#xff1f; 我先把最简单的方法告诉老师们&#xff0c;使用易查分&#xff0c;它可以帮助老师快速发布成绩&#xff0c;学生轻松查询&#xff…

vite 使用本地 ip + localhost 访问服务

vite 使用本地 ip localhost 访问服务 在 vite.config.js 中&#xff0c;如果未配置 server.host&#xff0c;默认服务将以 localhost 进行启动&#xff0c;此时我们可以通过 localhost:port 或 127.0.0.1:port 进行应用访问。 import { resolve } from path function pathRes…

05、SpringBoot 集成 RocketMQ

目录 SpringBoot集成RocketMQ消息发送三种方式1、同步消息producer-springboot创建项目添加依赖配置文件同步消息发送代码启动类Test类 comsumer-springboot创建项目添加依赖配置文件同步消息消费代码 2、异步消息生产者消费者 3、一次性消息生产者消费者 消息消费两种方式1、集…

使用 OAuth 和 OpenID Connect 进行升级身份验证

实现递增身份验证不需要让应用程序编排对多个复杂 API 的调用。 相反&#xff0c;通过利用开放标准中已有的功能&#xff0c;您可以使用所有应用程序最有可能已经在使用的协议库为所有应用程序构建低摩擦、无状态的递增身份验证。 在本文中&#xff0c;您将了解什么是递增身份…

uniapp checkbox样式失效,选中框选中按钮不显示

找了很多方法 最后网上一个博主找到了解决方法 在项目的main.css里面 如果你不知道你的css样式在哪个文件夹 直接全局搜索‘ 找到注释两个地方 第一个 checkbox::before 找到这一行 注释箭头指的地方就可以 第二个 checkbox .uni-checkbox-input::before, 注释这两个地方…

Leetcode hot 100之动态规划【递推公式】

目录 入门理解 斐波那契(Fibonacci&#xff09;数列&#xff1a;递归 数塔&#xff1a;递推 递推公式 最小路径和 遍历顺序 整数拆分&#xff1a;拆分为和&#xff0c;乘积最大化 背包&#xff1a;&#xff1a; ->装包 框架 01背包&#xff1a;不可复选 倒序遍历 …

Android 自定义view 圆形进度条

Android 自定义view 圆形进度条 前言一、码前分析二、开码1.画笔2.弧度3.圆弧的位置4.暴露给外部设置进度条的方法三、使用四、完整代码 总结 前言 先来看看效果&#xff0c;大概要实现这么一个圆形的进度条 一、码前分析 要实现这么一个进度条的效果&#xff0c;实际上是要画…

精彩再现!LLUG 深圳场成功举办 | 附活动资料下载

导读&#xff1a;9 月 24 日下午&#xff0c;龙蜥社区联合Linux 中国在深圳成功举办LLUG。本文转自Linux 中国&#xff0c;作者 Bestony。 9 月 24 日下午&#xff0c;龙蜥社区联合Linux 中国举办的 LLUG 在热浪滔天的深圳圆满落幕。 &#xff08;图/ 白板上的 “LLUG.sz”由 N…

哇喔,用这个平台制作电子画册,太简单了!

经常在朋友圈里看到可以在线浏览、类似仿真书的电子画册&#xff0c;总觉得这种制作起来很难&#xff0c;后来无意间看到朋友在制作&#xff0c;今天终于知道怎么做了&#xff01; 原来只用一个平台 FLBOOK&#xff01;&#xff01;就能做出来这种效果&#xff0c;像我这种电脑…

C/C++类型转换

目录 一、C语言中的类型转换二、C中的类型转换2.1 C的四种类型转换2.1.1 static_cast2.1.2 reinterpret_cast2.1.3 const_cast2.1.4 dynamic_cast 三、RTTI&#xff08;了解&#xff09;四、特殊的类型转换 一、C语言中的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧…

【Unity ShaderGraph】| 如何快速制作一个 马赛克效果 实战

前言 【Unity ShaderGraph】| 如何快速制作一个 马赛克效果 实战一、效果展示二、马赛克效果四、应用实例 前言 本文将使用Unity 的ShaderGraph制作一个马赛克的效果&#xff0c;可以直接拿到项目中使用。对ShaderGraph还不了解的小伙伴可以参考这篇文章&#xff1a;【Unity S…

2022最新版-李宏毅机器学习深度学习课程-P25 Spacial Transformer Layer

data augmentation/spacial transformer CNN 并不能够处理影像放大缩小,或者是旋转的问题。所以在做影像辨识的时候,往往都要做 Data Augmentation&#xff0c;把你的训练数据截一小块出来放大缩小、把图片旋转&#xff0c;CNN 才会做到好的结果。 有一个架构叫 spacial Tran…

Ubuntu 22.04.3 LTS单机私有化部署sealos desktop

推荐使用奇数台 Master 节点和若干 Node 节点操作系统 :Ubuntu 22.04 LTS内核版本 :5.4 及以上配置推荐 :CPU 4 核 , 内存 8GB, 存储空间 100GB 以上最小配置 :CPU 2 核 , 内存 4GB, 存储空间 60GB 这里采用的Ubuntu 22.04.3 LTS 版本&#xff0c;Ubuntu 20.04.4 LTS这个版本…

iOS——Manager封装网络请求

在之前的项目里&#xff0c;我们都是把网络请求写在viewController的viewDidLoad&#xff0c;而实际中使用的时候并不能这么简单&#xff0c;对于不同的需要&#xff0c;我们需要有不同的网络请求。所以我们可以用单例模式创建一个全局的Manager类&#xff0c;用实例Manager来执…

微信朋友圈的高级玩法!你一定要知道!

我们都知道&#xff0c;朋友圈是一个社交平台&#xff0c;可以让我们和朋友们分享生活中的点滴&#xff0c;看到他们的动态。但你可能不知道&#xff0c;朋友圈其实有很多高级玩法&#xff0c;可以让你的社交体验更加丰富多彩。今天&#xff0c;就让我们一起来看看朋友圈的那些…

协同办公系统OA实施过程中需要注意的细节

随着企业对于高效、便捷的办公方式的需求增加&#xff0c;协同办公系统OA正逐渐成为企业信息化建设的热门选择。然而&#xff0c;协同办公系统OA的实施并非一蹴而就&#xff0c;需要企业在实施过程中注意一系列的细节。 一、规划与需求分析 企业应根据自身的业务需求和发展战略…

天津滨海新区城市轨道交通电能管理系统方案与实施方案

【摘要】&#xff1a;介绍天津滨海新区轨道交通项目建设电能管理系统的系统架构、功能组成和实施方案。在借鉴其他城市轨道交通项目电能管理系统的基础上,结合天津滨海新区轨道交通建设的具体情况&#xff0c;对系统组网方案、测量表计设置原则、与通风空调节能系统和照明节能系…