in 操作系统 ~ read.
内存映射

内存映射

内存映射

内存

虚拟内存

将硬盘的部分区域作为内存使用,供内存换入换出,Linux的Swap空间。

RAM紧张时,将数据移动到分页文件空间(硬盘)

通常指按换入换出,换入换出逻辑基于LRU

具体Swap实现原理,待研究,与地址变换表有关,映射了RAM与硬盘的地址关系。

物理内存

物理内存条的内存空间。

Linux 内核给每个进程都提供了一个独立的虚拟内存空间,并且这个空间地址是连续的。虚拟内存空间的内部又被分为内核空间和用户空间两部分。所有进程的内核空间,关联的都是相同的物理内存
例如:
虚拟内存

内存管理需求

  • 抽象,即给每个程序逻辑地址空间
  • 保护,不同程序的地址空间互相隔离,无法越界访问
  • 共享,对于一些公共函数库,可以只在内存中存一份,其它程序引用这一个库即可
  • 虚拟化,通过逻辑地址和虚拟内存,可以使用更大的地址空间

地址

地址概念

简单理解:针对软件就讲逻辑地址,针对cpu就讲线性地址,针对硬件就讲物理地址

  • 虚拟地址(内核编程使用)/线性地址(Intel手册使用):

    0x08111111 地址就是虚拟地址,即虚拟内存的地址,是内存管理的抽象。
    有了这样的抽像,一个程序,就可以使用比真实物理地址大得多的地址空间。
    甚至多个进程可以使用相同的地址, 因为转换后的物理地址并非相同的。
    它是逻辑地址到物理地址变换的中间层,
    在段式存储中,逻辑地址是段中的偏移地址,然后加上基地址就是线性地址。

    程序产生逻辑地址,查找段表找到线性地址,如启用分页,则查找页表得到物理地址,否则线性地址就是物理地址

  • 逻辑地址:

    机器语言指令中,用来指定一个操作数或者是一条指令的地址。
    分配给程序使用的,生成依赖编译器,通常所有程序都会被分配4G虚拟内存。

    0x08111111的实际逻辑地址,在CPU看来为[A的代码段标识符: 0x08111111]

  • 物理地址:

    用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。
    真实物理内存的地址,是确定的,与逻辑地址不完全对应

物理地址空间,进程A、B的逻辑地址空间的关系:

memmap

逻辑地址生成

  1. 编译:将高级语言编译成汇编语言。假设此时此时地址已知,如果起始地址改变,必须重新编译
  2. 汇编:将汇编语言翻译长机器能够识别的二进制代码,里面的地址是该程序执行时,对应地址空间中的位置
  3. 链接:将程序执行需要的函数库链接到可执行文件中,更新地址空间
  4. 加载:将函数加载到内存中时根据程序块在内存中的位置更新逻辑地址空间内的地址(重定位)
  5. 执行:执行代码时,程序在内存中可能会移动,这里需要地址转换(映射)支持

proc_addr

:第4步,为进程生成自己的逻辑地址空间,通过地址映射,映射至物理地址空间

地址解析

  1. 首先,CPU中的算数逻辑单元看到的都是逻辑地址
  2. 当CPU需要把数据写入内存或从内存中读取时,MMU会把逻辑地址转换成对应的物理地址
  3. 控制逻辑把数据、操作请求和物理地址发送到总线,分为读请求和写请求
    ○ 写请求,则把数据写入内存
    ○ 读请求,则把数据从内存中读取发送给CPU

addr_parser

MMU负责逻辑地址和物理地址之间的转换,操作系统负责建立逻辑地址和物理地址之间的映射关系。

程序在执行时,CPU看到的是逻辑地址,当CPU读写数据时,由MMU根据逻辑地址找到对应的物理地址,然后到总线上读写数据。通过这种管理机制,可以更好地管理内存,在多道程序执行中做到隔离和共享。

逻辑地址(程序、段表) -> 线性地址(CPU、页表) -> 物理地址(硬件)

addrline

地址映射

Linux内存映射用页式存储管理,段式是Intel独有概念,Linux为遵守Intel规则,使用的都是相同的段地址,每个进程对应一套页表,通过对页表的管理实现内存的隔离和共享。

地址映射是一种多对一的关系,即不同的逻辑地址可以映射到同一个线性地址上;不同的线性地址也可以映射到同一个物理地址上

• 段式存储管理(segmentation)
• 页式存储管理(paging)
• 段页式存储管理(上面两者的综合)

段式存储管理

seg

不同的段的长度可以不同(通常情况下也都不一样),段的长度在运行期间可以动态改变

段式存储管理下的逻辑地址组成格式为(s, o),s为段号,o为段内偏移量,段号和对应内存中的物理起始地址由段表记录。寻址时,先根据段号到段表中查到物理起始地址(基址),然后加上偏移量,得到最终的物理地址。

线性地址:段起始地址+段内偏移量

页式存储管理

页式存储管理有两个至关重要的概念:

  1. 物理页帧(Frame | Page Frame | 帧 | 页帧):把物理地址空间分成大小相同的基本单位。大小为2^n,如512/4096等,通常为4K
  2. 逻辑页面(Page | 页):把逻辑地址空间划分为相同大小的基本单位
  3. 页帧大小和页面大小必须一致

页式存储管理的寻址方式和段式管理类似,逻辑地址格式为(p, o),表示页中的地址,其中p表示页号,o表示偏移量物理地址格式为(f, o),表示页帧中的地址,其中f表示页帧号,o表示偏移量,页偏移量和页帧偏移量是相等的。

页和页帧的对应关系使用页表(Page Table)来管理。寻址时首先根据页号找到页表中对应的页帧号,然后用得到的页帧号与偏移量组成实际的物理地址。

PageTable

:此处可以看出当物理内存为4G,则每个进程的逻辑内存为4G。

页面和页帧的大小相比分段要小得多,假设系统是32位,页帧大小1024字节,这样有2^32/2^10=2^22条页表记录,查询页表的时间要多很多。

提高页表性能的方法:
  1. 使用快表(Translation Look-aside Buffer, TLB):直译为旁路快表缓冲,可以理解为页表缓冲。即在内存和CPU之间搭建页表缓存,寻址时先到TLB中查找,未命中再到内存中的快表查找,TLB通常处于MMU中
  2. 多级页表:(p1, p2, o)是两级页表的虚拟地址表示,先根据p1查找页表1中的p2,再根据p2查询真正的页帧号,然后根据偏移地址o查到最终的物理地址

段和分页的比较

分页和分段系统有许多相似之处。两者都采用离散分配方式,且都要通过地址映射机构来实现地址变换。但在概念上两者完全不同,主要表现在下述三个方面:

  1. 页帧是信息的物理单位,分页是为了实现非连续分配,以便解决内存碎片问题, 提高内存的利用率。段是信息的逻辑单位,分段的目的是为了能更好地满足用户的需要
  2. 页的大小固定且由系统决定,由系统把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的,因而在系统中只能有一种大小的页面。而的长度却不固定,决定于用户所编写的程序,通常由编译程序在对源程序进行编译时,根据信息的性质来划分。
  3. 段式存储和页式存储都是为了更好管理内存,段式程序的角度入手,页式物理底层的角度入手,

在理解上,可以结合两者的优缺点进行选择:

分段 分页
优点 段长可动态修改,方便编程,分段共享,分段保护,动态链接,动态增长 非连续分配,减少内存碎片,提高内存利用效率
缺点 内部碎片,地址计算需要更多硬件支持 需要两次内存访问,页表可能很大

段页式存储管理

段页式存储管理充分利用了段式存储在内存保护方面有优势,页式存储在内存利用和优化转移到后备存储方面有优势。

在段式存储管理基础上,给每个段加一级页表。逻辑地址格式为(s, p, o),s为段号,p为页号,o为页内偏移。寻址时,现根据段号s查找段表中的页表地址,然后到页表中查找p对应的起始地址,最后加上偏移o得到最终的物理地址。

Reference

非原创,参考网络上诸多大佬的文章,依个人理解,整理而来。