首页 > 系统相关 >用户态内存映射

用户态内存映射

时间:2023-11-05 22:33:40浏览次数:30  
标签:里面 struct 映射 用户 页表 虚拟内存 内存

内存映射不仅仅是物理内存和虚拟内存之间的映射,还包括将文件中的内容映射到虚拟内存空间。这个时候,访问内存空间就能够访问到文件里面的数据。而仅有物理内存和虚拟内存的映射,是一种特殊情况。

用户态内存映射_虚拟内存

对于堆的申请来讲,mmap 是映射内存空间到物理内存。

如果一个进程想映射一个文件到自己的虚拟内存空间,也要通过 mmap 系统调用。这个时候 mmap 是映射内存空间到物理内存再到文件。

如果是匿名映射,则调用 mm_struct 里面的 get_unmapped_area 函数。这个函数其实是 arch_get_unmapped_area。它会调用 find_vma_prev,在表示虚拟内存区域的 vm_area_struct 红黑树上找到相应的位置。之所以叫 prev,是说这个时候虚拟内存区域还没有建立,找到前一个 vm_area_struct。

如果不是匿名映射,而是映射到一个文件,这样在 Linux 里面,每个打开的文件都有一个 struct file 结构,里面有一个 file_operations,用来表示和这个文件相关的操作。如果是我们熟知的 ext4 文件系统,调用的是 thp_get_unmapped_area。如果我们仔细看这个函数,最终还是调用 mm_struct 里面的 get_unmapped_area 函数。殊途同归。

 PGD、P4G、PUD、PMD、PTE四级页表的概念如下:

用户态内存映射_虚拟内存_02

pgd_t 用于全局页目录项,pud_t 用于上层页目录项,pmd_t 用于中间页目录项,pte_t 用于直接页表项。

一个进程的虚拟地址空间包含用户态和内核态两部分。为了从虚拟地址空间映射到物理页面,页表也分为用户地址空间的页表和内核页表,这就和上面遇到的 vmalloc 有关系了。在内核里面,映射靠内核页表,这里内核页表会拷贝一份到进程的页表。

cr3 是 CPU 的一个寄存器,它会指向当前进程的顶级 pgd。如果 CPU 的指令要访问进程的虚拟内存,它就会自动从 cr3 里面得到 pgd 在物理内存的地址,然后根据里面的页表解析虚拟内存的地址为物理内存,从而访问真正的物理内存上的数据。

这里需要注意两点。第一点,cr3 里面存放当前进程的顶级 pgd,这个是硬件的要求。cr3 里面需要存放 pgd 在物理内存的地址,不能是虚拟地址。因而 load_new_mm_cr3 里面会使用 __pa,将 mm_struct 里面的成员变量 pgd(mm_struct 里面存的都是虚拟地址)变为物理地址,才能加载到 cr3 里面去。

第二点,用户进程在运行的过程中,访问虚拟内存中的数据,会被 cr3 里面指向的页表转换为物理地址后,才在物理内存中访问数据,这个过程都是在用户态运行的,地址转换的过程无需进入内核态。

只有访问虚拟内存的时候,发现没有映射到物理内存,页表也没有创建过,才触发缺页异常。进入内核调用 do_page_fault,一直调用到 __handle_mm_fault,这才有了上面解析到这个函数的时候,我们看到的代码。既然原来没有创建过页表,那只好补上这一课。于是,__handle_mm_fault 调用 pud_alloc 和 pmd_alloc,来创建相应的页目录项,最后调用 handle_pte_fault 来创建页表项。

为了加快映射速度,我们不需要每次从虚拟地址到物理地址的转换都走一遍页表。

用户态内存映射_物理内存_03

页表一般都很大,只能存放在内存中。操作系统每次访问内存都要折腾两步,先通过查询页表得到物理地址,然后访问该物理地址读取指令、数据。

为了提高映射速度,我们引入了 TLB(Translation Lookaside Buffer),我们经常称为快表,专门用来做地址映射的硬件设备。它不在内存中,可存储的数据比较少,但是比内存要快。所以,我们可以想象,TLB 就是页表的 Cache,其中存储了当前最可能被访问到的页表项,其内容是部分页表项的一个副本。

有了 TLB 之后,地址映射的过程就像图中画的。我们先查块表,块表中有映射关系,然后直接转换为物理地址。如果在 TLB 查不到映射关系时,才会到内存中查询页表。



标签:里面,struct,映射,用户,页表,虚拟内存,内存
From: https://blog.51cto.com/key3feng/8196044

相关文章

  • 第二章 文件管理、第三章 用户管理
    第二章文件管理一、文件目录与路径/:根目录/bin:存放启动时所需要的普通程序/boot:存放内核及启动所需要的文件/dev:存放设备相关的文件/etc:存放系统的配置文件/home:存放用户文件的主目录,用户数据(cd~可进入自己的主目录)/lib:存放启动时所需要的库文件/roo......
  • Python 用户输入和字符串格式化指南
    Python允许用户输入数据。这意味着我们可以向用户询问输入。在Python3.6中,使用input()方法来获取用户输入。在Python2.7中,使用raw_input()方法来获取用户输入。以下示例要求用户输入用户名,并在输入用户名后将其打印在屏幕上:Python3.6:username=input("请输入用户名......
  • Python 用户输入和字符串格式化指南
    Python允许用户输入数据。这意味着我们可以向用户询问输入。在Python3.6中,使用input()方法来获取用户输入。在Python2.7中,使用raw_input()方法来获取用户输入。以下示例要求用户输入用户名,并在输入用户名后将其打印在屏幕上:Python3.6:username=input("请输入用户......
  • JavaScript内存管理——隐藏类
    根据JavaScript所在的运行环境,有时候需要根据JavaScript引擎采取不同的性能优化策略。如果代码非常注重性能,那么隐藏类对我们是非常重要的。比如以下的代码:functionUser(){this.name="UserName";}letuser1=newUser();leruser2=newUser();在上面的代码中......
  • 用户分类
         产品具有4个核心要素,用户,需求,场景,竞争优势。今天看了《人人都是产品经理2.0》记录一下我对用户的理解。     用户分为:目标用户,核心用户,种子用户等等,目标用户是指所有跟产品有关系的用户群体,而“核心用户”是指目标用户中最重要的那一部分人。     怎么从......
  • python的内存泄漏及垃圾回收机制
    python内存泄漏的几种场景: 一,如果打开一个文件,不关闭,是不是就是内存泄漏了? 在Python中,打开的文件对象会一直存在内存中,直到显式地关闭文件或者程序结束时才会被清理。因此,如果打开了一个文件但没有关闭它,那么这个文件对象会一直占用内存,导致内存泄漏。为了避免内存泄漏问题......
  • 关于虚拟机下Redhat7版本root用户密码忘记的解决方法
    关于虚拟机下Redhat7版本root用户密码忘记的解决方法一、开机二、出现这个不用管,点取消(没有出现也是正常的)三、出现这个,键盘敲e进入编辑四、鼠标移动到最下,在UTF-8后,写rd.break,然后ctrl+x进入到下一个环节五、等待出现命令行六、按顺序敲如下命令:七、注意此时的命......
  • 内存分配
    arena这块区域最大,明显就是用来存放我们最终的对象,里面分成了一个个8K大小的房间,每个房间我们称为page。(这里虽然写了它是512G,但是你心里要有B数,你电脑根本没这么大的内存,其实操作系统只是给了你地址而已)同时几个page组合在一起的大房间又叫做mspan(这个是golang中内存管理的基本......
  • 对象内存图的过程
     单一对象1.由于TestStudent中含有main方法,因此TestStudent类先以字节码形式进入方法区,里面包含main方法2.虚拟机调用该类中的main方法,main方法进入栈内存中3.main方法中先创建对象stu,调用了student类,Student类字节码文件进入方法区4.创建了对象stu,在堆内存中开辟对象stu......
  • Linux创建特定用户运行应用程序
    我们知道Linxu分为内核态和用户态,用户态和内核态交互的桥梁就是shell,用户的应用程序通常运行在用户态,也就是用户空间,默认情况下,root用户拥有系统最高权限,很多时候我们在linux部署应用程序时,程序可能需要取得某些系统权限才能正常运行,比如在所属组为root的目录里新建一个*.pid文件,......