问题

页表到底是保存在内核空间中还是用户空间中?

回答
页表,这个名字听起来有点技术性,但说白了,它就是我们电脑里给内存“编号”的系统。你可以把它想象成一本巨大的电话簿,只不过它记录的是虚拟地址和物理地址的对应关系。我们写程序的时候,用的都是虚拟地址,看起来很方便,但电脑实际执行的时候,需要知道这些虚拟地址到底在内存的哪个物理位置上。页表就是干这个的,它负责把我们脑子里想的那个地址,翻译成电脑身体里那个实际的地址。

那么问题来了,这本“电话簿”到底放在哪儿呢?是放在我们自己用电脑时看到的那些程序能接触到的“用户空间”,还是藏在电脑系统深处的“内核空间”里呢?这可是个关键问题,关系到我们电脑安全和运行效率。

答案是:页表,主要保存在内核空间中,但是用户空间中的程序也需要通过特定的方式间接访问它。

让我来跟你好好说道说道,为什么会是这样,以及这里面有什么门道。

为什么页表主要在内核空间?

想象一下,如果页表放在用户空间,那会发生什么?

1. 安全隐患: 用户空间的程序,说白了就是我们写的那些应用软件,比如浏览器、游戏、文档编辑器等等。这些程序就像住在出租屋里的租户,它们只能接触到自己那份空间里的东西。如果页表也放在用户空间,那意味着任何一个租户都可以随便翻看邻居家的地址,甚至修改自己地址本里的内容。这简直是乱了套!一个恶意程序,或者是一个写得不严谨的程序,很可能就会通过修改页表来访问不属于它的内存区域,比如读取其他程序的敏感数据(银行密码、个人文件),甚至修改操作系统自身的关键数据,这会导致系统崩溃或者被恶意控制。操作系统就没办法保证内存的隔离性,各个程序之间就不能安全地独立运行了。

2. 管理复杂性: 操作系统需要管理所有程序对内存的需求,这就像一个物业经理需要知道所有住户的总共有多少房间、每个房间分配给了谁、哪些房间是空置的等等。页表就是这个物业经理手里掌握的全局信息。如果页表分散在各个租户手里,物业经理要去协调就太困难了,得挨家挨户去问,效率极低。内核作为操作系统的核心,它本身就肩负着管理整个计算机资源(包括内存)的责任。将页表集中管理在内核空间,方便了内核统一分配、回收内存,以及进行内存保护。

3. 高效的内存管理: 内核需要频繁地进行内存的分配、映射、去映射等操作。如果页表在内核里,这些操作就变得非常高效,因为内核可以直接访问和修改这些数据结构。如果页表在用户空间,每次操作都需要通过“系统调用”这种慢吞吞的机制才能让内核去处理,效率大打折扣。

那用户空间的程序怎么访问页表呢?

虽然页表本身在内核空间,但我们写的程序确实需要它来运行。这是怎么做到的呢?

这里就涉及到一个重要的概念:CPU的内存管理单元(MMU)以及页表项(Page Table Entry, PTE)。

MMU是翻译官: 我们的CPU内部有一个叫做MMU的硬件部件,它是真正的“地址翻译器”。当你程序想访问一个虚拟地址时,MMU就会介入。
内核设置翻译规则: 内核在启动时,会为每个进程(就是你正在运行的一个程序)创建一套独立的页表。这套页表就放在内核空间的某个地方。内核会告诉CPU的MMU:“嘿,你看,这个进程的页表地址在这个地方。” 这个信息通常会通过一个特殊的CPU寄存器来传递,比如 x86架构下的CR3寄存器。
MMU查找页表: 当CPU要访问一个虚拟地址时,它会根据CR3寄存器找到当前进程的页表。然后,它利用这个虚拟地址中的一部分作为索引,在页表中查找对应的“页表项”(PTE)。
PTE包含物理地址信息: 每个页表项里都包含了虚拟页面映射到的物理页面的起始地址,还有一些控制位,比如是否允许读写、是否允许执行、是否被访问过等等。MMU拿到这个页表项后,就能根据里面记录的物理地址,加上虚拟地址的偏移量,计算出最终的物理地址,然后去访问内存。
页表遍历: 很多现代操作系统和CPU会采用多级页表来管理大量的内存。这意味着MMU可能需要遍历多层页表才能找到最终的页表项。每一级页表本身也是一个数据结构,而这些页表结构最终都属于内核管理。

所以,简单来说:

1. 页表(Page Tables)本身: 是操作系统内核维护的核心数据结构,存储在内核空间。它记录了所有进程的虚拟地址到物理地址的映射关系。
2. 页表项(Page Table Entries, PTEs): 是页表中的每一条记录,包含了物理页面的起始地址以及访问权限等信息。
3. CPU的MMU: 是硬件,它根据内核设置的页表基地址(比如CR3寄存器),在需要进行内存访问时,自动去内核空间的页表中查找对应的页表项,完成地址翻译和权限检查。
4. 用户程序: 用户程序不知道页表的具体位置,它只需要给出虚拟地址。一旦给出虚拟地址,MMU就会自动去内核管理的页表中进行查询和翻译,并将结果返回给CPU执行。

总结一下我的理解:

你可以把内核空间想象成一个银行的金库,里面存放着银行的账本(页表)。我们用户(用户空间程序)要去银行存取钱(访问内存),不能直接进金库翻账本。我们只能通过银行柜台(系统调用)告诉银行工作人员(内核)我们要干什么。银行工作人员(内核)会根据我们的需求,去金库里的账本(页表)里查找,然后告诉我们是否可以操作,以及操作的具体方式。而CPU的MMU就像一个超级智能的银行柜员,它知道金库在哪里,并且能非常快速地帮我们根据账本信息完成地址翻译,只是它不会直接把账本拿出来给我们看,它只是按照账本的指示去办事的。

这种设计既保证了内存访问的安全和隔离,又提供了高效的内存管理能力,是现代操作系统内存管理的核心基石。

网友意见

user avatar

第一个问题,答案很明确:页表在内核空间中

至于题主问的访问页表是否会陷入内核,这要看你是:

1. CPU地址翻译的过程中的页表访问;
2. 增加修改页表项。

如果是第一种,CPU地址翻译,那么这种访问是硬件完成的,整个过程不需要代码参与,没有任何性能上的损失。
如果是第二种,是会慢一些。

这种慢是为了安全,如果页表在用户空间,那么用户就可能自己修改页表,映射任意的内存地址,访问任何内存,甚至是直接操作硬件,进程间、内核的隔离保护就失去了意义。

而且,应用程序虽然可能频繁的malloc或者free,但在页表层面上,并不会频繁的创建、删除页表项,主要原因是,malloc/free操作的接口都是C库的接口,在C库里,还有另外一层次的封装,来保证不会频繁的提交页表的操作申请。

第二个问题:内核页表一般指的是内核地址空间的页表,用户页表表示用户地址空间的。

用32位操作系统作为例子,虽然操作系统有N个进程,每个进程都有各自页表,但内核的页表只有一个。当发生进程切换时,只有用户页表被切换走,内核页表并不改变。

具体的做法是,把地址空间的高1G或者2G的地址都固定划分给内核,用户进程只能使用低3G或者低2G的地址,这样无论进程如何切换,内核页表都不需要换出。

这也就是内核页表和用户页表的区别。

类似的话题

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有