一、概述

在Linux使用中,会发现Linux的空闲内存总是非常少,让人感觉内存总是不够用,其实这正是Linux内存管理的特性。

能使用的内存大小和CPU位数有关,在32位的CPU上,能用的内存大小是4G,在64位CPU上,是2^64。(这里不区分虚拟和物理)

二、分配流程

先了解内存分配的大概流程:

  1. 用户进程使用malloc介面分配虚拟内存
  2. 用户进程访问内存虚拟地址
  3. MMU单元将虚拟内存转换为物理内存
  4. MMU去内存读取页表
  5. MMU发现页表不存在,自动触发缺页异常(page fault)
  6. 执行内核中的page fault处理程序,分配物理内存,修改页表
  7. 异常处理完毕,返回步骤2执行相应的操作

两个名词概念

物理内存:对应物理上内存条上的内存(真实存在)

虚拟内存:从进程的角度看,是一个逻辑的概念(抽象存在)

三、分配细节

通过虚拟内存技术,让每个应用程序都认为自己拥有独立且连续的可用的内存空间(一段连续完整的地址空间),而实际上,它通常是被映射到多个物理内存段,还有部分暂时存储在外部磁碟存储器上,在需要时再载入到内存中来。

1、用户进程使用什么来进行虚拟内存的分配?

标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的

  • brk是将数据段(.data)的最高地址指针_edata往高地址推;
  • mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存

Malloc(<128K)时使用brk进行分配,malloc(>128K)时使用mmap进行分配

2、虚拟内存和物理内存的对应关系由谁来负责维护,如何对应?

  • 页表的创建和维护都是由操作系统内核负责的
  • 由页表来建立虚拟内存到物理内存之间的映射关系,页表就是在内存中的一张表,简单看做一张hash表,记录的是虚拟地址和物理地址的对应关系,每个虚拟地址对应一个表项,通过这张表,就能将虚拟地址转换为物理地址,也就能建立虚拟内存到物理内存的映射关系了

3、MMU去读取页表,那它是如何知道页表在哪的?

  • CPU上有特别的寄存器(CR3),向其中写入页表的地址,MMU就知道了

4、每个进程都有自己的页表,那MMU怎么知道读取哪张?

  • 操作系统在初始化或分配、释放内存时会执行一些指令在物理内存中填写页表,然后用指令设置MMU,告诉MMU页表在物理内存中的什么位置。

5、为啥页表会不存在呢?页表是何时创建的?

  • 在完成虚拟地址的分配后,这块内存一般是没有物理页与之对应的(即没有页表),等到进程第一次读写A这块内存的时候,发生缺页中断(page fault)

6、page fault是如何创建页表的?

  • page fault是硬体上的一种机制,当硬体检测到缺页异常时,主动触发,然后会自动跳转到异常处理程序处理。该异常处理程序是内核中提前注册好的,其中要做的主要操作,就是:分配物理内存,然后修改相应进程的页表,建立该物理内存和虚拟内存的映射关系(页表项)。异常跟中断类似,区别在于,中断是非同步的,由外设触发;异常是同步的,由CPU自己触发

四、开机时内存分配

开机时禁止了内存分页机制,这和原始的MS-DOS一样,只有1MB的可用存储地址空间,用户可以运行任何指令、也可以修改存储区域中的任何位置——在实模式中没有保护和特权指令的概念。

虽然在刚刚开机后只能使用1MB的存储地址空间,但是32位的Intel处理器第一条执行指令地址为0xFFFFFFF0(4GB存储空间的最后16位元组)

五、开机后内存分配

内存可用大小是和位数有关,以32位来说,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。

对linux操作系统而言,将最高的1G位元组(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G位元组(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。

PS:

内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据。不管是内核空间还是用户空间,它们都处于虚拟空间中。

六、MMU

  • 作用

内存管理单元作用:VA映射成PA

  • 页/页帧/页表/页表项(PTE)

MMU是负责把虚拟地址映射为物理地址,但凡"映射"都要解决两个问题:映射的最小单位(粒度)和映射的规则。

单位:MMU中VA到PA映射的最小单位称为页(Page),映射的最低粒度是单个虚拟页到物理页,页大小通常是4K。

页帧:是指物理内存中的一页内存,MMU虚实地址映射就是寻找物理页帧的过程。

页表:描述MMU的映射规则,即虚拟内存哪(几)个页映射到物理内存哪(几)个页帧。页表由一条条代表映射规则的记录组成。页表存储在内存中。

页表项:即页表中的每一条规则称为一个页表条目。

  • TLB

由于页表存储在内存中,MMU去访问内存中的页表很慢,所以就有了TLB(Translation Lookaside Buffers)。

就是MMU内部专用的存放页表的cache,保存著最近使用的PTE乃至全部页表。MMU接收到虚拟地址后,首先在TLB中查找,如果找到该VA对应的PTE就直接转换,找不到再去外存页表查找,并置换进TLB。TLB属于片上SRAM,访问速度快,通过TLB缓存PTE可以节省MMU访问外存页表的时间,从而加速虚实地址转换。

七、参考

闲聊Linux内存管理(1)?

happyseeker.github.io

Linux内存分配的原理--malloc/brk/mmap?

vinoit.me
图标
硬体篇之MMU - CSDN博客?

blog.csdn.net
图标

推荐阅读:

相关文章