# 基本概念

在引入多道程序后,不同程序间会出现资源共享,其中就包括主存储器的资源共享。于是,需要给出内存管理 (memory management) 策略,防止内存的数据混乱,提高程序并发执行的效率。

内存管理的主要功能包括:

  • 内存空间的分配与回收
  • 地址转换
  • 内存空间的扩充
  • 内存共享
  • 存储保护:保证各运行程序之间互不干扰。

# 程序运行的基本原理

# 程序的链接和装入

创建进程前要将程序和数据装入内存,包括编译链接装入三个步骤。

# 程序的链接

程序的链接包括静态链接装入时动态链接运行时动态链接三种方式。

# 程序的装入

程序的装入指将程序放入内存中,该过程通过装入程序完成。其包括绝对装入可重定位装入动态运行时装入三种方式。其中,绝对装入指将程序逻辑地址和物理地址完全对应地放入内存。而其余两种都实现了从虚拟地址物理地址的映射,该过程称为重定位 (relocation). 可重定位装入是在程序装入时就为程序分配了完整的内存空间,并实现了全部地址的重定位,且程序不能在内存中进行移动,因此称为静态重定位;而动态运行时装入是在程序的执行过程中才实现重定位,并在程序运行中为程序动态分配内存,因此称为动态重定位

# 内存虚拟化

CPU 生成的地址称为逻辑地址 (logical address) 或虚拟地址 (virtual address), 内存单元看到的地址存入内存地址寄存器 (memory-address register, MAR),称为物理地址 (physical address). 从虚拟地址到物理地址的映射由内存管理单元 (memory-management unit, MMU) 来完成。

# 可执行文件

可执行文件 (executable file) 是由机器语言 (二进制码) 组成的,计算机可以直接执行的文件。一般由高级语言经编译得到。

在不同操作系统中,可执行文件的格式不完全相同。例如,Windows 操作系统中的文件格式为 exe 文件,而类 Unix 系统中的可执行文件为 elf 文件。尽管文件格式不完全相同,但文件格式遵从相近的存储空间规划方式。

# EXE 文件

  • DOS 头:包含 DOS 操作系统相关信息,以支持早期的 DOS 操作系统的兼容性。
  • PE 头:PE 是 Portable Executable 的缩写,即可移植可执行文件。PE 头包含文件格式信息、程序入口地址、代码段、数据段、导入表、导出表、资源表、重定位表等信息。
  • 节表:节是 PE 文件的最小单元,每个节对应 PE 文件中的一个区段。节表中存储了每个节的名称、大小、偏移量等信息,用于操作系统在加载程序时按照指定的顺序进行组合。
  • 代码段:包含程序的指令集和函数体,用于程序的执行。
  • 数据段:包含程序的全局变量、常量和字符串等静态数据。
  • 初始化段 (.init 段):在程序启动时会被执行的代码段。
  • 未初始化数据段 (.bss 段):包含未初始化的全局变量和静态变量。
  • 导入表 (Import Table):包含程序依赖的外部库函数的名称和地址。
  • 导出表 (Export Table):包含程序可供外部调用的函数名称和地址。
  • 资源表 (Resource Table):包含程序使用到的资源,如图标、位图、字符串等。
  • 重定位表 (Relocation Table):当程序被加载到内存中时,由于内存地址的变化,需要对程序中的地址进行修正。

# Reference

  • 《Windows PE 文件格式》(微软官方文档):https://docs.microsoft.com/zh-cn/windows/win32/debug/pe-format
  • 《PE 头结构分析》(博客文章):https://www.cnblogs.com/tianshui/p/9647194.html
  • 《Windows PE 文件格式详解》(博客文章):https://www.cnblogs.com/vamei/archive/2012/12/01/2802811.html
  • 《PE 文件格式详解》(博客文章):https://www.cnblogs.com/ycb1688/p/5708652.html

以上资料详细介绍了 PE 文件的结构和各个部分的作用,其中包括 DOS 头、PE 头、节表、代码段、数据段、初始化段、未初始化数据段、导入表、导出表、资源表和重定位表等部分。这些资料可以作为参考,更好地了解 PE 文件的构成和格式。

以上关于可执行文件的内容来自 ChatGPT , 未经整理,准确性难以保证。

# ELF 文件

ELF 文件是类 Unix 中的可执行文件格式,全称可执行可链接文件 (executable and linkable format, ELF).

# Reference

  • CSDN: 可执行目标文件的结构
  • Wikipedia: Executable and Linkable Format

# 进程的内存映像

# 内存保护

在内存管理的过程中,对每一个进程,通过两个寄存器对进程所占的地址进行保护。两个寄存器为基地址寄存器 (base register, 又称重定位寄存器) 和界限地址寄存器 (limit register, 又称限长寄存器)。前者指定了该进程最小的合法物理地址,后者指定了进程占据内存的最大范围大小。两寄存器的加载都需要操作系统通过特权指令进行。

# 内存扩充

覆盖交换技术是内存扩充的两种方法。

# 内存分配

# 连续内存分配

将多个进程同时放置于同一块内存时,若将每个进程放置于一个连续的内存区域,那么称这种方式为连续内存分配 (contiguous memory allocation)。连续内存分配包括单一连续分配固定分区分配动态分区分配

# 单一连续分配

# 固定分区分配

固定分区分配就是将内存分为多个固定大小的分区 (partition)。每个分区只包含一个进程。

容易产生较多的内碎片 (internal fragmentation).

# 动态分区分配

动态分区分配又称可变分区分配,指进程在装入内存时,根据内存的实际需要,动态为进程分配内存,石洞分区的大小恰好适合进程的需要。

该方法容易产生较多的外碎片 (external fragmentation)。克服外部碎片采用紧凑 (compaction) 技术解决。

其中,寻找空闲内存的常用方法包括:

  1. 首次适应 (first-fit):找到大小满足要求的第一个空闲分区。通常是最好的和最快的,但在内存低地址处会出现许多小的外碎片。
  2. 邻近适应 (next-fit)
  3. 最优适应 (best-fit):找到第一个能满足要求的最小的空闲分区。
  4. 最差适应 (worst-fit):找到第一个能满足要求的最大的空闲分区。

# 分段

# 基本概念

分段的思想来自于 8086 设计。在 8086 中,由于寄存器长度为 16 位,而内存空间为 20 位,因此需要借助两个寄存器实现内存寻址,且内存地址的表示可以不是唯一的。因此,我们将代码中的一个逻辑块用几个段存储。例如,简单的汇编程序中也有数据段、代码段等。

严谨点地说, (segment) 是用户作业中具有逻辑意义的一部分。分段 (segmentation) 是以段为单位进行内存分配和管理的内存管理模式。

# 硬件

# 段表

段表 (segment table) 中的每个条目都有段基地址 (segment base) 和段界限 (segment limit)。

# 分页

# 缺页率

# 虚拟内存管理

# 虚拟内存技术

虚拟内存技术是基于局部性原理的高速缓存技术。在虚拟内存技术的支持下,系统可以为用户提供一个看起来比实际内存容量大得多的存储器,即虚拟存储器。虚拟存储器包括多次性对换性虚拟性三个主要特征,其中虚拟性是最重要的特征。虚拟内存技术的实现主要包括请求分页存储管理请求分段存储管理请求段页式存储管理三种方式。

# 请求调页存储管理

# 页表机制

# 缺页中断