内存管理单元

<image>

内存管理单元（memory management unit，缩写为MMU），有时称作分页内存管理单元（paged memory management unit，缩写为PMMU）。它是一种负责处理中央处理器（CPU）的内存访问请求的计算机硬件。它的功能包括虚拟地址到物理地址的转换（即虚拟内存管理）、内存保护、中央处理器高速缓存的控制，在较为简单的计算机体系结构中，负责总线的仲裁以及存储体切换（bank switching，尤其是在8位的系统上）。

在现代系统中，程序通常使用可访问计算机架构理论最大内存容量的地址，即32位或64位地址。MMU将各程序的地址映射到物理内存中相互独立的区域，而物理内存的容量通常远小于理论最大值。这一机制得以实现，是因为程序在任一时刻实际使用的内存量通常较为有限。

大多数现代操作系统（Operating System，OS）均与MMU协同工作，以提供虚拟内存（Virtual Memory，VM）支持。MMU以固定大小的存储块（称为页面或页）为单位追踪内存使用情况。若程序引用某个不在物理内存中的页面位置，MMU将向操作系统发送中断信号。操作系统随即选择一个使用频率较低的内存块，若该块自载入后已被修改，则将其写入后备存储器（如硬盘），随后从后备存储器读取所需页面至该内存块，并配置MMU将该内存块映射至程序最初请求的页面，以供程序使用。这一过程称为请求分页（Demand Paging）。部分较为简单的实时操作系统（Real-Time Operating System，RTOS）不支持虚拟内存功能，因此无需MMU，但仍需配备硬件存储保护单元（Memory Protection Unit）。

MMU通常提供存储保护（Memory Protection）功能，阻止程序访问其未曾申请的内存区域，从而防止行为异常或恶意的程序修改或读取其他程序的数据。

在某些早期微处理器设计中，存储管理功能由独立的集成电路实现，例如VLSI Technology公司的VI475（1986年）、与Motorola 68020处理器配套用于Macintosh II计算机的Motorola 68851（1984年），以及与Zilog Z8000系列处理器配套使用的Z8010和Z8015（1985年）。后续微处理器（如Motorola 68030和Zilog Z280）将MMU与中央处理器集成于同一集成电路芯片上，Intel 80286及后续x86系列微处理器亦采用此设计。

## 工作机制

早期系统采用基址-界限寻址（Base and Bounds Addressing）技术，该技术进一步发展演变为分段（Segmentation）机制；亦有系统采用固定存储块集合，而非按需载入。这两种方法的根本区别在于连续内存块的大小：分页系统（Paged Systems）将主存储器划分为一系列等尺寸的存储块，而分段系统（Segmented Systems）通常允许使用可变尺寸的存储块。

### 分段转换

在分段转换（Segmented Translation）机制中，内存地址由段号（Segment Number）和段内偏移量（Offset within the Segment）两部分构成。段具有可变长度，并可关联访问权限属性，如读（Read）、写（Write）和执行（Execute）权限。段被载入物理内存中的连续区域。通常，段号用作段表（Segment Table）的索引；段表中的每个条目包含该段所在物理内存区域的地址、段长度，以及权限标志等其他信息。

此种方式的优势在于结构简洁：由于内存块连续，映射过程仅需存储基址（Base）和界限（Limit）两个数值即可。

该方法的缺陷在于会导致一种称为外部碎片（External Fragmentation）的现象。当内存分配被释放但释放区域不连续时，便会产生外部碎片。此时，系统中可用内存总量虽足以满足请求，但由于这些内存分散分布，无法分配给单个段使用。在程序频繁启动和终止的系统中，随着时间推移，内存可能变得高度碎片化，导致不存在足够大的连续块；此时需将段在内存中移动，并修改其段表项以反映新的物理地址，从而腾出足够大的连续空间以容纳该段。

部分型号的 PDP-11 16位小型计算机配备分段存储管理单元，具有一组页面地址寄存器（Page Address Registers，PARs）和页面描述寄存器（Page Description Registers，PDRs）；该机制将16位虚拟地址映射为18位物理地址。PDP-11/70 型号进一步扩展为22位物理地址。分段机制在1980年代的微型计算机平台上得到广泛应用。采用此概念的MMU包括 Motorola 68451 和 Zilog Z8010，但亦存在诸多其他实例。

Intel 8086、Intel 8088、Intel 80186 及 Intel 80188 提供基础的存储分段功能，但不具备存储保护机制。（每个段的每个字节始终对任何程序可见。）16位段寄存器支持65,536个段；每个段起始于固定偏移量，该偏移量等于段号乘以16；段起始地址粒度为16字节。每个段允许对64 KiB（65,536字节）的地址空间进行读写访问（此限制由16位程序计数器PC和堆栈指针SP寄存器设定；处理器不进行边界检查）。偏移量与地址之和超过0xFFFFF时，将回绕至0x00000。每个64 KiB段与后续4,095个段重叠；每个物理地址可由4,096组段-偏移量对表示。该方案仅能寻址1 MiB（1024 KiB）的物理内存（及内存映射I/O）。（可选的扩展内存硬件可在软件控制下增加存储体切换内存。）后续x86处理器自 Intel 80286 起支持真正的分段映射，并配备段表。

### 分页转换

在分页转换（Paged Translation）机制中，地址空间（即处理器使用的地址范围）被划分为若干页面（Pages），每个页面的大小为2的幂次方，通常为数千字节，但也可能更大。程序使用机器的自然地址大小引用内存，在现代系统中通常为32位或64位。地址的低位部分（即页内偏移量）保持不变；高位部分则为虚拟页号（Virtual Page Numbers）。

大多数MMU使用内存中的页表（Page Table）作为条目列表，每个虚拟页对应一个页表项（Page Table Entry，PTE），用于将虚拟页号映射到主存储器中的物理页号。为减少页表尺寸，常采用多级页表（Multi-Level Page Tables）。PTE的相联缓存（Associative Cache）称为转译检测缓冲区（Translation Lookaside Buffer，TLB），用于避免每次映射虚拟地址时都访问主存储器。

其他MMU可能采用私有内存数组、一组寄存器，或一层或多层静态随机存取存储器（Static RAM）数组来存储映射信息集合。

MMU将虚拟地址划分为虚拟页号和页内偏移量。虚拟页号用于选择页表项；若找到该页表项，且页面标记为在内存中，则将页表项中的物理页号与偏移量组合，构建对应于该虚拟地址的物理地址。

虚拟页号可直接用作页表或其他映射信息的索引，亦可进一步划分：某层地址位用作低级表索引，下一层地址位用作更低级表索引，形成两层或更多层索引结构。

分页转换存在一个问题：随着虚拟地址空间扩展，保存映射信息所需的内存量亦随之增加。例如，在68020处理器中，地址宽度为32位，若页面大小为8 kB，则虚拟页号为地址的高19位，单级页表大小将达512 kB。在1980年代，对于内存中的页表，这可能占机器主存储器的相当比例；对于将页映射存储于静态RAM的MMU，则可能需要大量昂贵的静态RAM。此问题可通过增大页面尺寸来缓解，例如由8 kB增至64 kB。此时页索引使用16位，生成的页表大小为64 kB，更为可行。然而，增大页面尺寸会导致第二个问题：内部碎片（Internal Fragmentation）增加。若程序连续请求小块内存，将被分配大块内存，从而造成大量内存浪费。

若地址空间稀疏，即并非所有区域均已分配，则可通过使用多级页表或静态RAM映射来缓解该问题，且无需为空闲区域分配全部所需的页表项。

分页转换方法在1970年代和1980年代的微处理器MMU中得到广泛应用，包括68020的68851、68030的片上MMU、Zilog Z8000的Z8015，以及NS32000系列的NS16082。

页表项或其他每页信息还可能包含以下信息：页面是否已被写入（脏位，Dirty Bit）、上次使用时间（访问位，Accessed Bit，用于最近最少使用（Least Recently Used，LRU）页面置换算法）、可读写该页面的进程类型（用户模式或管理模式），以及是否应缓存该页面。

有时，页表项或其他每页信息可能禁止访问特定虚拟页，原因可能是该虚拟页未分配物理随机存取存储器（Random-Access Memory，RAM）。此时，MMU向CPU发出缺页中断（Page Fault）信号。操作系统随即处理该情况，可能尝试寻找空闲RAM帧并设置页映射以将其映射至请求的虚拟地址。若无空闲RAM，则可能需要使用某种置换算法选择现有页面（称为牺牲页，Victim），并将其保存至磁盘（此过程称为页面置换，Paging）。某些MMU可能出现PTE短缺，此时操作系统必须释放一个PTE以建立新映射。

对于非法或不存在内存访问，MMU还可能分别产生非法访问错误（Illegal Access Error）条件或无效缺页中断（Invalid Page Fault），由操作系统处理时导致段错误（Segmentation Fault）或总线错误（Bus Error）。

分页转换缓解了内存外部碎片（External Fragmentation）问题。内存块分配和释放后，空闲内存可能变得碎片化（不连续），导致最大连续空闲块远小于空闲内存总量。借助虚拟内存，连续的虚拟地址范围可映射至若干不连续的物理内存块；这种不连续分配是分页的优势之一。

然而，分页转换导致另一个问题——内部碎片。当程序请求的内存块无法完整映射到页面时，便会产生内部碎片。例如，若程序请求1 KB缓冲区用于文件操作，该请求将导致整个页面被分配，尽管仅使用1 KB；若页面大于1 KB，则页面剩余部分被浪费。若进行大量此类小块分配，即使大量内存仍为空，内存也可能被耗尽。

### 分段与分页结合

部分系统（如 GE 645 及其后继机型）同时采用分段和分页两种机制。此类系统的段表（Segment Table）并非包含各段的条目（给出段的物理基址和长度），而是包含给出该段页表物理基址的条目，同时保留段的长度信息。物理内存被划分为固定大小的页面，纯分页机制中使用的请求分页技术同样适用于段页结合的请求分页机制。

Signetics 68905 MMU 专为 Motorola 68000、68010 及 68012 微处理器设计，支持分段和分页功能。Signetics 和 Philips 均生产了将 68905 与处理器集成于同一物理芯片上的 68000 版本，即 68070。

### IOMMU

执行直接内存访问（Direct Memory Access，DMA）的硬件完全绕过CPU的MMU。部分I/O系统允许DMA硬件使用物理地址（Physical Addresses）直接对物理RAM中的任意位置进行读写，且不受任何限制。其他I/O系统则配备独立的MMU，称为输入输出内存管理单元（Input-Output Memory Management Unit，IOMMU），可由操作系统编程配置，将DMA硬件发出的设备地址（Device Addresses）转换为由操作系统指定的特定受限物理页面。IOMMU可用于阻断DMA攻击（DMA Attacks）。

## 益处

MMU可提供存储保护（Memory Protection）功能，使得代码试图访问或修改其无权访问的数据时操作失败；该机制既能捕获软件缺陷，亦能阻止对数据的蓄意访问或修改。通常，操作系统为每个程序分配独立的虚拟地址空间（Virtual Address Space）而不会让程序直接访问物理内存。这种内存保护特性可以避免某个程序非法访问其他程序的虚拟内存空间。有时候软件自身的错误会引发页错误，这时内存管理单元可以检测到页错误，然后通知操作系统终止出错的程序。

当虚拟地址空间过小时，MMU亦可用于扩展物理地址空间的大小。例如，PDP-11 最初采用16位地址，随着1970年代存储器容量增长，该地址宽度逐渐不敷使用。对此，系统将物理存储器总线扩展至18位，并利用MMU根据处理器总线上的其他引脚指示当前访问存储器的程序，从而添加两个附加地址位。

此外，内存管理单元能够减少程序的内存碎片化现象。也就是说，当程序分配并释放内存块后，可分配的连续内存块的最大尺寸亦远小于尚未分配的内存量。虚拟内存机制可以在内存分页机制的基础上，将多个不连续的物理内存区块映射为一个连续的虚拟内存块。