【Linux的内存管理】

为什么需要内存管理

    • 分段和分页
      • 内存分段
      • 内存分页
    • 分页情况下,虚拟内存如何映射到物理地址
    • 页表原理
      • 多级页表
    • TLB快表
    • 段页式内存管理
    • 需要为什么进程地址空间
    • Linux的进程虚拟地址空间
    • 管理进程地址空间
      • 如何分配虚拟内存
      • 虚拟内存的管理
        • 程序编译后的二进制文件如何映射到虚拟内存空间中
    • 内核的虚拟地址
      • 虚拟内核空间进行动态映射
    • 物理内存地址
    • cpu读取内存的数据
    • Linux的物理和虚拟内存的页都是4KB的大小

在计算机中运行的进程,都是二进制代码&数据&内核的数据结构组成,这些内容都需要物理内存进行保存。许多的进程直接使用这些物理内存,操作系统是非常难对指向物理内存进行管理的,如果一个进出现了问题,就有可能会影响其他的进程。所以有了进程地址空间,而且是每一个进程独有的且和其他的进程地址空间隔离,即使该进程出现了问题也不会造成其他进程的问题。在Linux中,如果是32位的相同,进程地址空间可以表示的区域有4GB的大小。其中1GB的内核空间是所有进程共享的。有了进程地址空间,相当于为每个进程提供了一个自己独立的内存区域,且每个区域都是4GB的大小,就可以访问到比真实的物理地址大的空间。
在这里插入图片描述

分段和分页

在Linux中。

  • 分段:可以为每一个每一个进程分配不同的线性地址空间,不同的段有着不同的功能,有代码段,数据段,堆区栈区。每一段都是连续的空间。
  • 分页:将整个虚拟和物理内存的空间划分成许多连续的小块空间,这样的小块空间就是页,在物理内存中为页框,在Linux中,每一个页的大小的空间为4KB。

内存分段

分段机制下的虚拟地址有两部分组成,段的选择因子和段内的偏移量。

  • 段的选择因子:段的选择因子有段号,段号,段寄存器通过段号找到对应的段表,段表有对应的段描述符,段描述符有段的完整信息,段的基地址、段的界限和特权等级等。
  • 段内的偏移量:偏移量在0和段的界限之间,段基地址加上偏移量再通过虚拟到物理地址的转化,就可以访问到物理地址了。
    在这里插入图片描述

分段会产生内存碎片问题,产生的原因是,申请段大小的空间,申请多少就会有多少,然后不同的段大小是不一样的,这就会导致有些区域空间无法申请成功,操作系统就会再其他可以申请的区域申请,就会导致无法申请的区域浪费掉,这就是外部的内存碎片问题。

内存分页

分段能连续分配空间,但因为有些空间不足,无法申请,但是这种情况又无法避免,只能减少。内存不足的情况下,如果进程需要物理内存,操作系统会将一部分的内存数据交换出去,让当前的进程有一定的物理空间使用。然而数据的交互是需要耗时的,这时候我们就需要减少内存的交换,面对这种情况,

  • 我们可以将虚拟和物理的内存进行分页,页与页之间是紧密排列的,所以不会有外部碎片。
  • 页与页之间是紧密排列的,所以不会有外部碎片。有了分页,内存需要置换的话,不需要把一整个段置换,只需要将需要的页进行置换即可,可以提高效率。

分页情况下,虚拟内存如何映射到物理地址

虚拟和物理地址的转化,是由一个页表来进行的。提供虚拟和物理地址的映射。虚拟地址由页号和偏移量。

  • 页号:页号作为页表的索引,提高页号找到对应物理地址。
  • 偏移量:通过偏移量,更加页号找到的物理地址进行偏移量的计算来获取目标的地址。
    在这里插入图片描述

页表原理

页表的存在,让虚拟和物理地址有了联系。一个页或页框是4KB的大小,虚拟和物理地址是4GB的大小,就会有4 * 1024 * 1024 / 4个页或页框(一百多万的页),一个页表的大小就要4MB的大小,如果进程过多的话,采用这样的页表方式,将会浪费物理内存。

多级页表

采用多级页表就可以解决页表占用空间过多的问题。第一个页表大小为4KB,有1024个页表项,而页表项不存储虚拟地址,而是存储二级页表的页号,二级页表也是一个4KB大小的页表,也有1024个页表项,在极端场景下就能表示4GB的空间大小。32位情况下,前10比特位表示一级页表,中间10位表示二级页表,后12位表示物理地址的偏移量。
在这里插入图片描述

一级页表4KB+二级页表4MB的情况 > 一个页表4MB:这让看,会发现使用二级页表会比直接使用一个页表还多4KB,极端情况是这样的。但一个进程在运行的时候,并不是一定需要4GB的空间大小,有些进程还不一定把他的全部数据加载到物理内存当中。这时候,一级页表创建的时候,有些页表项不会被使用到,二级页表就不会存在,如果需要的话,再创建二级页表。如果只使用了20%的二级的页表,一级加二级页表所占的内存只需要0.804MB,远比只使用一个页表更节省空间。

TLB快表

如果每次都虚拟地址都通过页表找到对应的物理地址,效率会很慢,所以计算机科学家在CPU芯片中加入了一个Cache,就是TLB快表,用于存放将虚拟地址映射至物理地址的标签页表条目。有了TLB的缓存,避免每次都要查询页表项,每次CPU访问某个地址的时候,现在TLB缓存中查询,如果查询到有对应的虚拟到物理的映射,则直接通过MMU内存管理单元进行虚拟到物理的访问,减少了页表查询的消耗。
在这里插入图片描述

  • 首先,CPU进行虚拟地址寻址时,首先会在MMU的TLB快表缓存当中寻找是否有虚拟地址到物理地址的页表条目,如果存在,直接通过MMU访问物理地址。
  • 如果TLB缓存没有,则会发生硬件中断,将外设的资源加载到内存当中,页表重新映射虚拟地址到物理地址的页表条目,然后再将该页表条目缓存在TLB,方便下次的快速查找。

段页式内存管理

分段可以让内存空间分为多个有目的逻辑段,不同的数据存放在不同的段空间,分页将多个分段的空间划分为大小一致的许多连续的空间,可以在磁盘和物理内存进行交换的数据减少,提高效率。就可以使用段号,段内页号,页号偏移进行虚拟到物理地址的映射。

  • 访问段表查询段号,得到段内的页表地址。
  • 通过页表找到物理页号。
  • 在通过偏移量的条件下,得到物理地址。

需要为什么进程地址空间

  • 进程的地址空间其实并没有进程需要的数据,数据而是在物理内存当中,所以进程地址空间的内存也是虚拟内存。
    在这里插入图片描述
  • 如果所有的进程都直接使用物理内存,如果其中一个进程修改其他进程的物理内存的数据,就会有可能导致进程的崩溃,所以,为了不同的进程安全,则使用进程地址空间作为间接的访问真实的物理内存,并通过进程地址空间和物理空间的转化,来对内存进行访问。进程之间互不干涉。在操作系统中,通过CPU的MMU对虚拟地址对物理地址的转化来找到真实的物理内存。
  • 如果可执行二进制代码运行多个进程,地址都是物理地址的话,就会指向同一块物理内存,导致程序出错或崩溃。如果重新为每一个进程直接分配物理内存,那会非常的复杂,调试的时候,程序员就难以区分地址。
    在这里插入图片描述
  • 使用了虚拟内存,直接可以让程序员看到的是连续的地址,虽然底层物理的内存是不连续的。每个进程的地址空间互相独立,互补干扰,其中的一个进程崩溃,不会影响其他的进程,即使虚拟地址一样,通过虚拟转物理的技术,不同进程的物理地址是不会发生冲突的。
    在这里插入图片描述

Linux的进程虚拟地址空间

在这里插入图片描述

  • 在Linux中,进程地址空间不是一开始就是在最小地址初开始的,而是在0x0804 8000 地址开始。在0x0000 0000 到 0x0804 8000是一段不可访问的空间。因为数值较小,通常会被认为是一个不合法的地址,比如C语言的无效指针NULL,指向的就是这块区域。
  • 代码区:包括二进制可执行代码;
  • 数据区:包括已初始化的静态常量和全局变量;
  • BSS:未初始化的数据区;
  • 堆区:内核使用start_brk标识堆的起始位置,brk标识堆的结束位置。当申请新的内存空间时,只需要将brk指针增加到对应的大小,回收时减少对应大小即可。
  • 共享映射区:包括动态库,共享内存,堆空间申请;
  • 栈:存放局部变量的数据,和函数调用的上下文。有固定的大小,可以调整。在内核中,使用start_stack标识栈的起始地址,RSP寄存器保存栈顶指针,RBP寄存器保存栈基地址;
  • 内核空间:每一个进程都共用同一个1GB的内核地址空间;

管理进程地址空间

Linux中的进程使用一个结构体mm_struct来描述进程地址空间的,mm_struct是进程控制块task_struct的一个结构。每个进程的mm_struct都是独立的互不干扰。task_size其实是用户态可以访问的空间,task_struct就划分了用户态和内核态了。

struct task_struct{unsigned long task_size;//可以访问的大小 0xc0000000struct mm_struct *mm;
}

如何分配虚拟内存

根据mm_struct不同的定义进行划分。
在这里插入图片描述

  • start_code和end_code标识代码段开始和结尾,就是存放二进制代码的区域。
  • start_data和start_data是定义了的数据段的开始和结束的区域,后边紧跟着BSS未初始化的数据。
  • start_brk就是动态申请空间的堆区域的开始,brk标识申请的空间的结束位置,低地址往高地址增加。
  • mmap就是内存的映射区的开始,高地址往低地址增加。运行时所依赖的动态链接库就是加载到该内存区域。
  • start_stack是栈的起始位置,栈使用的空间是由高地址往低地址使用,结束的位置的至就在寄存器的栈顶指针。

虚拟内存的管理

mm_struct对虚拟空间进行划分,现在使用新的结构体vm_area_struct对这些区域进行管理。每个vm_area_struct对应一个划分的区域。然后使用类似链表的结构进行组织。

struct mm_struct{struct vm_area_struct  *mmap; /* list of VMAs */
}
struct vm_area_struct {struct mm_struct * vm_mm;	/* The address space we belong to. */unsigned long vm_start;		/* Our start address within vm_mm. */unsigned long vm_end;		/* The first byte after our end addresswithin vm_mm. *//* linked list of VM areas per task, sorted by address */struct vm_area_struct *vm_next;struct anon_vma *anon_vma;	/* Serialized by page_table_lock */unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZEunits, *not* PAGE_CACHE_SIZE */struct file * vm_file;		/* File we map to (can be NULL). */}
  • vm_mm标识该虚拟内存管理属于哪个空间,进行指针的回指到属于那块虚拟内存区域;
  • vm_start标识虚拟划分空间的起始地址,vm_end标识结束地址;
  • vm_next标识下一个vm_area_struct 的划分,内存的划分管理使用链表进行管理;
  • anon_vma标识的是匿名映射区,当进程动态申请的空间大于128kb的时候,则会在该区域申请空间,而不是通过堆区域的brk的指针往上增长,而是调用mmap申请空间。当mmap为文件申请空间的时候,vm_file属性就用来关联被映射的文件,这样虚拟内存就可以和映射的文件关联起来。vm_pgoff则标识映射到虚拟内存中的文件内容的偏移量。

在这里插入图片描述

程序编译后的二进制文件如何映射到虚拟内存空间中
  • 编译后的文件是elf格式的可执行文件,当执行elf格式的文件时,会将二进制代码加载到内存当中。
  • 通过内核函数load_elf_binary将elf的文件映射到虚拟地址空间。当fork创建子进程,exec进行进程替换的时候,执行二进制程序的时候,建立虚拟内存映射。初始化虚拟内存所需要的数据。

内核的虚拟地址

在32位的计算机下,虚拟内核空间在0xc000000到0xffffffff的区域,每个进程都是共有这块虚拟内存空间的。在内核低地址的896MB的空间,是一块直接映射的区域。直接映射到物理内存的0~896MB的区域。虽然是直接映射的区域,但虚拟内核空间还是使用了页表进行虚拟到物理的映射。只是说每次的映射的物理内存的地址是不会改变的。
在这里插入图片描述

  • 在这段896MB的物理内存当中,第1MB在系统启动的时候就已经被占用,1MB之后存放的内核的代码段,数据段,BSS段等。内核的elf格式的代码在启动的时候加载到内存当中。
  • 高端内存:在剩下的4GB- 896MB的3200MB的物理内存就是高端内存,是无法直接映射到内核虚拟空间剩下的128MB的空间的。所以只能动态的映射到虚拟内存的128内存当中,哪些使用先映射,使用完毕的话,可以让其他要映射的覆盖上去。

虚拟内核空间进行动态映射

虚拟内存采用函数vmalloc调用申请空间的,申请的虚拟空间是连续的,但物理空间不一定是连续的。然后通过页表的映射来进行虚拟到物理的转化。
在这里插入图片描述
malloc和vmalloc的区别

  • malloc用于用户申请堆上空间,是C标准库的函数。vmalloc是Linux内核提供的函数,用于内核中分配虚拟地址连续但物理地址不连续的空间。
  • malloc申请的大小没有特别的限制,但受到系统可用内存的限制。vmalloc申请的空间也没有大小的限制,适用于较大内存的场景。
  • malloc申请的的内存在虚拟地址是连续的,但物理地址是否连续取决内存管理器的实现和系统内存碎片的情况。malloc和vmalloc申请的空间都不会自动的初始化。
  • vmalloc在内核中执行,可能会阻塞,在调用vmalloc时一般不会被中断,系统调用的执行被视为一个原子操作,即在执行期间不会被中断。这是为了确保在系统调用服务例程执行期间对内核数据结构的一致性和完整性。系统调用执行的时间相对较短,内核会采取一些机制来防止在其执行期间被中断。
  • malloc调用是C标准库的函数调用,如果申请的空间大于堆可用的空间,malloc就会调用brk()或mmap()系统调用。用户态->内核态,如果申请的空间在堆区域满足,则直接在用户态就可以申请到,不需要到内核态。

物理内存地址

内存也叫随机访问存储器(RAM),分为静态SRAM和动态DRMA。

  • SRAM用于CPU的三级缓存的高速缓存,越靠近CPU的SRAM运行速率越快,但相应的容量也会越少。
    在这里插入图片描述
  • DRAM常用于主存上,运行速率相对高速缓存是慢的,但容量也比高速缓存大。内存是由多个存储器模块组成,存储器模块又包含着8个DRAM芯片。每一个DRAM芯片是由一个二维矩阵组成的。矩阵中每个元素称为supercell超单元,大小位一个字节,每个单元都有坐标。提高行列坐标进行寻找。存储控制器将物理地址转化位DRAM芯片的坐标,然后找到对应的位置将数据发到存储控制器。
    在这里插入图片描述

cpu读取内存的数据

  • 1:CPU获取到虚拟地址,通过MMU内存管理单元对虚拟地址进行物理地址的转化,将物理地址作为地址信号放在系统总线上传输,随后在I/O桥将系统总线上的地址喜欢转化为存储中小的电子信号。
  • 2:主存的存储控制器收到电子信号的物理地址,存储控制器找到对应存储模块的DRAM地址,然后获取数据。
  • 3:存储控制器读取的数据放到存储总线上,存储总线通过I/O桥,I/O将数据信号转化为系统总线的数据信号进行传递。
  • 4:CPU 芯片感受到系统总线上的数据信号,将数据从系统总线上读取出来并拷贝到寄存器中。

在这里插入图片描述

Linux的物理和虚拟内存的页都是4KB的大小

页的大小规定为2的整数次幂,因为有利于计算机的位运算,提高运行的效率。如果内存不足的情况下,有些进程需要使用到内存,操作系统就会将一些不太使用的物理页进行换入换出,还有内存和磁盘文件都会有交互,交互都是要消耗时间的。如果内存和磁盘直接传输小块数据是速度比较快的。所以内核默认采用4KB的大小。

  • 页表过小:虽然传输的效率会变快,内部的碎片也会减少,但需要的页表项就会增多,如果要页表的换入换出,就会涉及过多的页表,频繁的换入换出会更耗时,降低效率。
  • 页表过大:大的页表会减少页表一定的内存消耗,但会导致内部碎片增多。页大小过大,搜索页表会加快一定速率,但搜索页内的内容,要比页小的耗时。大的页和磁盘的每次交互或者换入换出的消耗更多的时间。综合来看4KB的大小更合理。

Linux中,使用struct page对物理页进行管理内核如何描述物理内存页。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文笔记:微表情欺骗检测

整理了AAAI2018 Deception Detection in Videos 论文的阅读笔记 背景模型实验可视化 背景 欺骗在我们的日常生活中很常见。一些谎言是无害的,而另一些谎言可能会产生严重的后果。例如,在法庭上撒谎可能会影响司法公正,让有罪的被告逍遥法外。…

TIM(Timer)定时器的原理

一、介绍 硬件定时器的工作原理基于时钟信号源提供稳定的时钟信号作为计时器的基准。计数器从预设值开始计数,每当时钟信号到达时计数器递增。当计数器达到预设值时,定时器会触发一个中断信号通知中断控制器处理相应的中断服务程序。在中断服务程序中&a…

启动redis

1. 进入root的状态,sudo -i 2. 通过sudo find /etc/redis/ -name "redis.conf"找到redis.conf的路径 3. 切换到/etc/redis目录下,开启redis服务 4. ps aux | grep redis命令查看按当前redis进程,发现已经服务已经开启 5.关闭服务…

【Linux】进程控制(创建、终止、等待、替换)

文章目录 1. 进程创建2. 进程终止3. 进程等待4. 进程程序替换4.1 认识进程替换4.2 认识全部接口 1. 进程创建 如何创建进程我们已经在之前学习过了,无非就是使用fork(),它有两个返回值。创建成功,给父进程返回PID,给子进程返回0&…

解决:使用layui.treeTable.updateNode,更新表格数据后,done里面的事件丢失问题

1. 背景 在给树形表格添加行点击事件,并且只更新当前行数据。 treeTable.updateNode("SpeProjListId", result.LAY_DATA_INDEX, result);更新数据后,点击事件失效。 1. 给字段绑定事件: class"link_a link_style" , {…

AI2.0时代,普通小白如何通过AI月入30万

最近这2年AI真的太火了,很多人都在讨论怎么用AI赚钱、提高效率。其实,我觉得AI并没有那么复杂,尤其是如果你不做AI底层研究,只是利用它来帮你省事、提效、赚钱,那就像当初学用电脑、用手机一样简单。你不需要懂AI的技术…

论文阅读:PET/CT Cross-modal medical image fusion of lung tumors based on DCIF-GAN

摘要 背景: 基于GAN的融合方法存在训练不稳定,提取图像的局部和全局上下文语义信息能力不足,交互融合程度不够等问题 贡献: 提出双耦合交互式融合GAN(Dual-Coupled Interactive Fusion GAN,DCIF-GAN&…

Oracle 数据库安装和配置详解

Oracle 数据库安装和配置详解 Oracle 数据库是一款功能强大、广泛使用的企业级关系数据库管理系统 (RDBMS),适用于处理大型数据库和复杂事务。本文将介绍如何在 Linux 和 Windows 环境下安装 Oracle 数据库,并对其进行基本配置,帮助开发者快…

国外电商系统开发-运维系统拓扑布局

点击列表中设备字段,然后定位到【拓扑布局】中,可以看到拓扑发生了变化 再回头,您再次添加一个服务器到系统中,并且选择该服务器的连接节点为您刚才创建的“SDN路由器”,保存后,您可以看到这个服务器连接着…

红帽操作系统Linux基本命令2( Linux 网络操作系统 06)

本文接着上篇Linux常用命令-1继续往后学习其他常用命令。 2.3 目录操作类命令 1.mkdir命令 mkdir命令用于创建一个目录。该命令的语法为: 上述目录名可以为相对路径,也可以为绝对路径。 mkdir命令的常用参数选项如下。 -p:在创…

通过dem2terrain生成MapboxGL地形服务

概述 MapboxGL在2的版本之后通过地形服务开始支持三维的展示了,之前也有文章“mapboxGL2中Terrain的离线化应用”对该服务进行过说明与分析。前些天在翻公众号的时候翻到了dem2terrain可以生成地形服务,同时做了一些优化,今天就给大家分享一…

畅享免费服务:PDF 转图片在线转换软件的魅力

为了方便在社交媒体上分享文档内容,还为了更好地适应特定的编辑需求,将 PDF 文件转换为图片格式都具有重要的意义。而如今,幸运的是,有许多pdf转图片在线转换免费工具为我们提供了便捷、高效的 PDF 转图片服务。接下来&#xff0c…

MongoDB 数据库服务搭建(单机)

下载地址 下载测试数据 作者:程序那点事儿 日期:2023/02/15 02:16 进入下载页,选择版本后,右键Download复制连接地址 下载安装包 ​ wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-5.0.14.tgz​ …

Redis: Sentinel哨兵监控架构及环境搭建

概述 在主从模式下,我们通过从节点只读模式提高了系统的并发能力并发不断增加,只需要扩展从节点即可,只要主从服务器之间,网络连接正常主服务器就会将写入自己的数据同步更新给从服务器,从而保证主从服务器的数据相同…

SQL自用小结

推荐一下这个知识点总结 《数据库系统概论》第五版 学习笔记总目录 1. SQL概述 SQL(Structured Query Language,结构化查询语言)是一种用于定义、查询、更新和控制关系数据库的标准化语言。 它包含了数据定义语言(DDL&#xff0…

51单片机系列-按键检测原理

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 独立按键是检测低电平的。 下面我们来看一张对应的电路原理图: 在这张图当中,P1,P2,P3内部都上拉了电阻,但是P0没有&am…

码随想录算法训练营第62天|卡码网:97. 小明逛公园、127. 骑士的攻击

1. 卡码网 97. 小明逛公园 题目链接:https://kamacoder.com/problempage.php?pid1155 文章链接:https://www.programmercarl.com/kamacoder/0097.小明逛公园.html 思路: 使用Floyd 算法,目的是解决多源最短路问题,即 …

Java项目实战II基于Java+Spring Boot+MySQL的房产销售系统(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者 一、前言 随着房地产市场的蓬勃发展,房产销售业务日益复杂,传统的手工管理方式已难以满…

机器学习/数据分析--用通俗语言讲解时间序列自回归(AR)模型,并用其预测天气,拟合度98%+

时间序列在回归预测的领域的重要性,不言而喻,在数学建模中使用及其频繁,但是你真的了解ARIMA、AR、MA么?ACF图你会看么?? 时间序列数据如何构造???,我打过不少…

EEPROM读写实验——FPGA学习笔记18

一、EEPROM简介 Electrically Erasable Progammable Read Only Memory:是指带电可擦可编程只读存储器,是一种常用的非易失性存储器(掉电数据不丢失) EEPROM发展历史 我们这次实验所用的AT24C64存储容量为64Kbit,内部分成256页&am…