【Linux】分页式存储管理:深刻理解页表映射

📝前言:

这篇文章我们来讲讲Linux------分布式存储管理

🎬个人简介:努力学习ing

📋个人专栏:Linux

🎀CSDN主页 愚润求学

🌄其他专栏:C++学习笔记C语言入门基础python入门基础C++刷题专栏


分布式存储管理

  • [一, 物理内存管理](#一, 物理内存管理)
  • 二,两级页表的地址转换
    • [1. 页表](#1. 页表)
    • [2. 页目录结构](#2. 页目录结构)
    • [3. 地址转换过程](#3. 地址转换过程)
    • [4. TLB](#4. TLB)
  • [三. 缺页异常](#三. 缺页异常)
    • 其他问题理解
      • [1. 理解malloc和new](#1. 理解malloc和new)
      • [2. 理解写时拷贝](#2. 理解写时拷贝)

一, 物理内存管理

我们之前谈磁盘的时候说数据是按块(4KB)存储的,实际上内存也是会按4KB大小来划分的。(物理内存和磁盘之间,以4KB为单位交换)

4GB 的空间就是4GB/4KB = 1048576 个块,我们把这个块称为:页框 page(一个页框对应到虚拟地址里称为页)

所有的页框,也需要描述 + 组织 ,在内核中用结构体struct page

cpp 复制代码
/* include/linux/mm_types.h */
struct page
{
    /* 原⼦标志,有些情况下会异步更新 */
    unsigned long flags;
    union
    {
        struct
        {
            struct list_head lru;
            struct address_space *mapping;
            /* 在映射内的偏移量 */
            pgoff_t index;
            unsigned long private;
        };
        struct
        { /* slab, slob and slub */
            union
            {
                struct list_head slab_list; /* uses lru */
                struct
                { /* Partial pages */
                    struct page *next;
#ifdef CONFIG_64BIT
                    int pages;    /* Nr of pages left */
                    int pobjects; /* Approximate count */
#else
                    short int pages;
                    short int pobjects;
#endif
                };
            };
            struct kmem_cache *slab_cache; /* not slob */
            /* Double-word boundary */
            void *freelist; /* first free object */
            union
            {
                void *s_mem;            /* slab: first object */
                unsigned long counters; /* SLUB */
                struct
                {                        /* SLUB */
                    unsigned inuse : 16; 
                    unsigned objects : 15;
                    unsigned frozen : 1;
                };
            };
        };
        ...
    };
    union
    {
        atomic_t _mapcount;
        unsigned int page_type;
        unsigned int active; /* SLAB */
        int units;           /* SLOB */
    };
    ...
#if defined(WANT_PAGE_VIRTUAL)
        void *virtual;
#endif /* WANT_PAGE_VIRTUAL */
    ...
}
  • flags :用来存放页框的状态。这些状态包括页框是不是脏的,是不是被锁定在内存中等。flag的每⼀位单独表⽰⼀种状态,所以它⾄少可以同时表示出32种不同的状态
  • _mapcount :表示在页表中有多少项指向该页框,也就是这⼀页框被引用了多少次。当计数值变为-1时,就说明当前内核并没有引用这⼀页框,于是在新的分配中就可以使用它
  • virtual :是页框的虚拟地址。通常情况下,它就是页框在虚拟内存中的地址

所有的Page通过一个全局的 struct page 数组来管理,每个下标就对应一个Page

二,两级页表的地址转换

1. 页表

实际上,页表中并不是存储每个字节的地址,而页(Page)级别的映射。即:存储每个页框的起始虚拟地址,然后映射到页框的起始物理地址

如果整个物理内存映射到整个虚拟空间上,则如下如:

4GB/4KB = 1048576,所以页表中只需要存储2^20个地址。

但是,如果每个页表都这么大,还是太多了,于是就有了利用页目录结构的分级页表。

2. 页目录结构

把拥有2^20个项的页表再按2^10为一块划分,分成2^102^10块,于是第一个2^10成了页目录,第二个2^10才对应到真正的页表。

这就是二级页表结构,32位机器就常用这种划分方法

  • 31- 22位表示页目录的下标,第21 - 12位表示页表内的下标
  • 最后11- 0位(低12位)则是具体的地址在页框内的偏移量
  • 所以我们通过虚拟地址映射到页框的起始物理地址,然后起始物理地址 + 偏移量,就可以定位到某个字节的地址

则,在这种结构下:

  • 每个进程有自己的页目录(PDE 表,一级表),存储在内存中,并由 CR3 寄存器(x86)指向其物理地址。
  • 页表(PTE 表,二级表) 按需分配,只有当进程实际使用某块虚拟地址时,才会分配对应的页表。
    • 如果某块 4MB 的虚拟地址范围未使用,对应的页表可以不分配(只需在页目录中标记 P=0),而不是占用完整的 2^20 个 PTE。

3. 地址转换过程

假设我们现在拿到了一个虚拟地址,转换流程:

  1. 从 CR3 寄存器获取页目录的物理地址(CR3 存储当前进程的页目录基址)。
  2. 虚拟地址的 31-22 位作为页目录索引 ,找到对应的 PDE。
    • 检查 PDE 的 P 位,如果为 0,触发 缺页异常(Page Fault)。
  3. 从 PDE 中取出页表的物理地址。
  4. 虚拟地址的 21-12 位作为页表索引 ,找到对应的 PTE。
    • 检查 PTE 的 P 位,如果为 0,触发 缺页异常。
  5. 从 PTE 中取出物理页框号(PFN)(页框的物理起始地址)。
  6. 物理地址 = (PFN << 12) | 页内偏移(低 12 位)

以上工作都是由MMU(内存管理单元)硬件完成

但是,每次MMU都要先进行两次页表查询确定物理地址还是太慢了,于是就有了快表TLB(缓存)

【我们可以通过物理地址来找到对应的虚拟地址,有对应的宏可以帮助我们实现,原理也很简单,只需要针对性的拿地址中的数字,反映的就是下标】

4. TLB

  • 当CPU给MMU发了一个新的虚拟地址以后,MMU先去TLB里面找有没有
  • 如果没有,就再进行两次页表查询,找到了以后吧地址返回给CPU,并且把这条映射关系给到TLB,让它记录一下

三. 缺页异常

当CPU 给 MMU 的虚拟地址,在 TLB 和页表都没有找到对应的物理页时,会引发缺页异常 Page Fault,它是⼀个由硬件中断触发的可以由软件逻辑纠正 的错误。

缺页中断会交给 PageFaultHandler 处理,其根据缺页中断的不同类型会进行不同的处理:

  • Hard Page Fault(硬缺页错误/主要缺页错误):这时物理内存中没有对应的物理页,需要CPU打开磁盘设备读取到物理内存中,再让MMU建⽴虚拟地址和物理地址的映射。
  • Soft Page Fault(软缺页错误/次要缺页错误):这时物理内存中是存在对应物理页的,只不过可能是其他进程调入的(比如动态库),发出缺页异常的进程不知道而已,此时MMU只需要建立映射即可。
  • Invalid Page Fault(无效缺页错误) :如,内存地址越界访问,对空指针解引用等,内核就会报 segment fault 错误,中断进程直接挂掉

其他问题理解

1. 理解malloc和new

  • 实际上mallocnew开空间并没有开实际的物理空间,而是只分配了进程地址空间。(当虚拟空间分配好以后,OS就认为这是合法的,属于该进程的空间了,用mm_struct记录)
  • 当真正要使用的时候,会触发中断错误,CPU去执行中断处理方法,然后真正分配空间,建立映射
    • 分配内存本质上是:找到空闲的物理页框,并填充到页表中
  • 这是一种内存的延迟申请,可以实现把"暂时没用到"的物理内存先给别人用

所以我们申请内存,实际上只是申请的进程地址空间

2. 理解写时拷贝

  • 子进程和父进程指向的其实是同一个页框,权限管理以页框为单位
  • 当一个进程写入时,发现权限不对,触发缺页
  • 然后,CPU就会去中断向量表执行中断处理方法,对整个页框写时拷贝

🌈我的分享也就到此结束啦🌈

要是我的分享也能对你的学习起到帮助,那简直是太酷啦!

若有不足,还请大家多多指正,我们一起学习交流!

📢公主,王子:点赞👍→收藏⭐→关注🔍

感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

相关推荐
AlfredZhao13 小时前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户97183563346619 小时前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪20 小时前
linux 拷贝文件或目录到指定的位置
linux
大树882 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质2 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
小宇宙Zz2 天前
Maven依赖冲突
java·服务器·maven
Inhand陈工2 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信