> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-yi-bu-fen-gai-lan/2.5.-cun-chu-guan-li.md).

# 2.5 存储管理

每个进程都有自己的私有地址空间。地址空间划分为三个逻辑段：正文段（text）、数据段（data）和栈段（stack）。正文段只读，存放程序的机器指令。数据段和栈段都可读可写。数据段存放程序的已初始化和未初始化数据部分，栈段则承载应用程序的运行时栈。在多数机器上，栈段随进程执行由内核自动扩展。数据段可以通过系统调用显式扩展或收缩，而正文段的大小只有在用文件系统的数据覆盖其内容时、或调试时才能改变。子进程各段的初始内容是父进程各段的副本。

进程执行并不需要其地址空间的全部内容都驻留内存。进程引用到地址空间中不在主存驻留的部分时，系统会把必要的信息调页进内存。系统资源紧张时，系统用两级办法维持可用资源：若内存尚有一定余量，系统会从最近未使用这些资源的进程那里收回内存资源；若资源严重短缺，系统就把进程的整个上下文交换到辅存。系统实施的请求调页和交换对进程实际上是透明的。不过，进程可以把预期的未来内存使用情况告知系统，以此辅助性能优化。

**BSD 存储管理设计决策**

4.2BSD 的一项需求是支持大型稀疏地址空间、映射文件和共享内存。当时定义了一个称为 `mmap()` 的接口，允许无关进程把一个文件映射进自己的地址空间。如果多个进程把同一文件映射进各自的地址空间，一个进程对地址空间的改动将反映到其他进程映射的区域以及文件本身。最终，4.2BSD 发布时并没有包含 `mmap()` 接口——让联网等其他特性及时问世的压力占了上风。

`mmap()` 接口的后续开发在 4.3BSD 的工作期间继续进行。40 多家企业和研究团体参与了讨论，形成了《Berkeley 软件体系结构手册》\[Joy et al., 1986] 所描述的修订架构。其中几家公司实现了修订后的接口 \[Gingell et al., 1987]。

时间压力再一次使 4.3BSD 未能提供这一接口的实现。尽管它可以构建在现有的 4.3BSD 虚拟存储系统之上，开发者还是决定不这样做，因为那个实现已有近 10 年历史。此外，原来的虚拟存储设计基于这样的假设：计算机内存小而贵，磁盘则本地相连、快速、大容量而且便宜。于是，虚拟存储系统的设计在内存使用上锱铢必较，不惜产生额外的磁盘流量。再加上 4.3BSD 的实现到处都是对 VAX 存储管理硬件的依赖，妨碍了向其他计算机体系结构的移植。最后，当时的虚拟存储系统并非为支持紧耦合多处理器而设计，而这种机器如今正日益普遍、日益重要。

试图渐进改良旧实现似乎注定失败。而全新的设计则可以利用大内存、节省磁盘传输，并有可能运行在多处理器上。4.3BSD 发布之时，新的虚拟存储实现完成的寥寥无几。因此，种种设计备选尚未经过检验，最优选择仍属未知。希望正确的选择会逐渐清晰，并且能够以这些新实现的工作为基础，为下一个伯克利 UNIX 系统打造出全新的虚拟存储系统。

虚拟存储系统的另一个问题，是系统调用时信息传入内核的方式。UNIX 总是把数据从进程地址空间复制到内核的缓冲区。对传输大量数据的读写操作来说，复制可能相当耗时。替代复制的办法是把进程内存重映射进内核。4.3BSD 内核总是复制数据，理由有如下几条：

* 用户数据常常既不按页对齐，也不是硬件页长的整数倍。
* 如果页被从进程那里拿走，进程将无法再引用这一页。有些程序依赖缓冲区里的数据在写完之后仍然保留。
* 如果允许进程保留该页的一个副本（按现行 4.3BSD 语义），该页就必须做成写时复制。写时复制的页通过设为只读来防止写入。进程试图修改该页时，内核收到写故障，随即为进程制作一个可以修改的副本。遗憾的是，典型进程拿到副本后马上就会往缓冲区写新数据，数据终究还是被复制了一遍。
* 4.3BSD 的虚拟存储设计没有为写时复制做准备。
* 页被重映射到新的虚拟内存地址时，多数存储管理硬件要求有选择地清洗硬件地址转换高速缓存。这种清洗往往很慢。最终结果是：对小于 4 至 8 KB 的数据块，重映射比复制还慢。

内存映射最大的推动力，是访问大文件和在进程之间传递大量数据的需要。`mmap()` 接口将让这两类工作都不必复制。

**内核内部的存储管理**

4.3BSD 内核至少有 10 种不同的内存分配器。有的处理大块内存，有的处理小而链式的数据结构，还有的包含描述 I/O 操作的信息。这些分配常常只是为了单个系统调用期间的短暂需要。在用户进程中，这种短期内存会分配在运行时栈上。内核的运行时栈有限，在栈上分配哪怕中等大小的内存块都不可行。因此，这类内存必须通过更动态的机制分配。例如，系统翻译路径名时，必须分配一个 1 KB 的缓冲区来容纳名字。

另一些内存块必须比单个系统调用更持久，因而即使栈上有空间也不能分配在栈上。例如协议控制块，它在网络连接的整个存活期间都存在。

随着服务越加越多，内核对动态内存分配的需求有增无减。每当出现新类型的内存分配需求，开发者就编写一套专门的内存分配方案来应对。新方案往往构建在旧分配器之上。例如，块设备子系统通过分配空缓冲区提供一种粗糙的内存分配形式。这种分配很慢，因为其中隐含的语义是：要找到最旧的缓冲区，若内容为脏则写到磁盘，再把物理内存移进或移出缓冲区以凑出请求的大小（见 7.5 节）。为了减少开销，又为路径名翻译造了一个“新”内存分配器：它分配一池空缓冲区，把它们挂在空闲表上，从而可以快速分配和释放 \[McKusick et al., 1985]。

这种内存分配方法有三个缺点。第一，新分配器只能处理有限的大小范围。第二，它挪用本该用于缓冲磁盘块的内存，耗竭缓冲池。第三，它又造出一个内核程序员必须了解的接口。

通用的内存分配器能降低内核代码编写的复杂度。内核不再提供许多半专门的内存分配途径，而是提供一个单一的通用分配器。只有一个接口，程序员就不必操心哪种分配方式最合适。一个好的通用分配器有助于避免不断发明新的专用分配器的综合征。

4.3BSD Tahoe 发行版引入了一个内存分配器，其接口类似为应用程序提供内存分配的 C 库例程 `malloc()` 和 `free()` \[McKusick & Karels, 1988]。与 C 库接口一样，分配例程接受一个参数指明所需的内存大小。内存请求的大小范围不受限制；不过，分配的是物理内存，不参与调页。释放例程接受一个指向被释放存储的指针，但不要求给出内存块的大小。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-yi-bu-fen-gai-lan/2.5.-cun-chu-guan-li.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
