# 17.1 应用程序使用虚拟内存所需要的特性

今天的话题是用户应用程序使用的虚拟内存，它主要是受这篇1991年的[论文](https://pdos.csail.mit.edu/6.828/2020/readings/appel-li.pdf)的启发。

首先，你们已经知道了，操作系统内核以非常灵活的方式使用了虚拟内存Page Table。你们已经通过Lazy Allocation Lab，Copy on Write Lab，以及XV6中的各种内存实现了解到了这一点。而今天论文中的核心观点是，用户应用程序也应该从灵活的虚拟内存中获得收益，也就是说用户应用程序也可以使用虚拟内存。用户应用程序本身就是运行在虚拟内存之上，我们这里说的虚拟内存是指：User Mode或者应用程序想要使用与内核相同的机制，来产生Page Fault并响应Page Fault（注，详见Lec08，内核中几乎所有的虚拟内存技巧都基于Page Fault）。也就是说User Mode需要能够修改PTE的Protection位（注，Protection位是PTE中表明对当前Page的保护，对应了4.3中的Writeable和Readable位）或者Privileged level。今天的论文，通过查看6-7种不同的应用程序，来说明用户应用程序使用虚拟内存的必要性。这些应用程序包括了：

* Garbage Collector
* Data Compression Application
* Shared Virtual Memory

![](/files/-MWbFyFIQzNPxi7SMh-f)

你可以发现这都是一些非常不同的应用程序，并且它们都依赖虚拟内存的一些特性来正常工作。所以第一个问题是，上面的应用程序需要的特性是什么？所以我们先来讨论一下需要的特性是什么？

* 首先，你需要trap来使得发生在内核中的Page Fault可以传播到用户空间，然后在用户空间的handler可以处理相应的Page Fault，之后再以正常的方式返回到内核并恢复指令的执行。这个特性是必须的，否则的话，你不能基于Page Fault做任何事情。
* 第二个特性是Prot1，它会降低了一个内存Page的accessability。accessability的意思是指内存Page的读写权限。内存Page的accessability有不同的降低方式，例如，将一个可以读写的Page变成只读的，或者将一个只读的Page变成完全没有权限。
* 除了对于每个内存Page的Prot1，还有管理多个Page的ProtN。ProtN基本上等效于调用N次Prot1，那为什么还需要有ProtN？因为单次ProtN的损耗比Prot1大不了多少，使用ProtN可以将成本分摊到N个Page，使得操作单个Page的性能损耗更少。在使用Prot1时，你需要修改PTE的bit位，并且在Prot1的结束时，需要清除TLB（注，详见4.4 Translation Lookaside Buffer），而清除TLB比较费时。如果能对所有需要修改的内存Page集中清理一次TLB，就可以将成本分摊。所以ProtN等效于修改PTE的bit位N次，再加上清除一次TLB。如果执行了N次Prot1，那就是N次修改PTE的bit位，再加上清除N次TLB，所以ProtN可以减少清除TLB的次数，进而提升性能。
* 下一个特性是Unprot，它增加了内存Page的accessability，例如将本来只读的Page变成可读可写的。
* 除此之外，还需要能够查看内存Page是否是Dirty。
* 以及map2。map2使得一个应用程序可以将一个特定的内存地址空间映射两次，并且这两次映射拥有不同的accessability（注，也就是一段物理内存对应两份虚拟内存，并且两份虚拟内存有不同的accessability）。

![](/files/-MWbe7Z9v3NOu6Bl3yeo)

XV6在用户程序中支持以上任意的特性吗？除了有类似于trap及其相关的alarm hander之外，XV6不支持任何一个以上的特性。XV6只有一个最小化的Unix接口，并不支持以上任何虚拟内存特性。尽管在XV6的内核中包含了所有的可用的虚拟内存的机制，但是并没有以系统调用的形式将它们暴露给用户空间。论文的观点是，任何一个好的操作系统都应该以系统调用的形式提供以上特性，以供应用程序使用。

所以自然的，这就引出了另一个问题，当今的Unix系统的功能范围是什么？以上特性属于Unix的范畴吗？如果你查看现在的Unix系统，例如Linux，你会发现，或许并不与论文中描述的完全一样，但是这些特性都存在。在论文那个年代（1991年），某些操作系统只包含了部分以上特性，但是如今这些特性都已经在现代的Unix系统中广泛支持了。接下来我们看一下如何实现这些特性。


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mit-public-courses-cn-translatio.gitbook.io/mit6-s081/lec17-virtual-memory-for-applications-frans/17.1-ying-yong-cheng-xu-shi-yong-xu-ni-nei-cun-suo-xu-yao-de-te-xing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
