【虚拟内存 & I/O & 零拷贝】这个问题一般通过多级页表(Multi-Level Page Tables)来解决,通过把一个大页表进行拆分,形成多级的页表,我们具体来看一个二级页表应该如何设计:假定一个虚拟地址是 32 位,由 10 位的一级页表索引、10 位的二级页表索引以及 12 位的地址偏移量,则 PTE 是 4 字节,页面 page 大小是 2^12 = 4KB,总共需要 2^20 个 PTE,一级页表中的每个 PTE 负责映射虚拟地址空间中的一个 4MB 的 chunk,每一个 chunk 都由 1024 个连续的页面 Page 组成,如果寻址空间是 4GB,那么一共只需要 1024 个 PTE 就足够覆盖整个进程地址空间 。二级页表中的每一个 PTE 都负责映射到一个 4KB 的虚拟内存页面,和单页表的原理是一样的 。
多级页表的关键在于,我们并不需要为一级页表中的每一个 PTE 都分配一个二级页表,而只需要为进程当前使用到的地址做相应的分配和映射 。因此,对于大部分进程来说,它们的一级页表中有大量空置的 PTE,那么这部分 PTE 对应的二级页表也将无需存在,这是一个相当可观的内存节约,事实上对于一个典型的程序来说,理论上的 4GB 可用虚拟内存地址空间绝大部分都会处于这样一种未分配的状态;更进一步,在程序运行过程中,只需要把一级页表放在主存中,虚拟内存系统可以在实际需要的时候才去创建、调入和调出二级页表,这样就可以确保只有那些最频繁被使用的二级页表才会常驻在主存中,此举亦极大地缓解了主存的压力 。

文章插图
二、 内核空间 & 用户空间
对 32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间)为 4G(2 的 32 次方) 。也就是说一个进程的最大地址空间为 4G 。操作系统的核心是内核(kernel),它独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限 。为了保证内核的安全,现在的操作系统一般都强制用户进程不能直接操作内核 。具体的实现方式基本都是由操作系统将虚拟地址空间划分为两部分,一部分为内核空间,另一部分为用户空间 。针对 linux 操作系统而言,最高的 1G 字节(从虚拟地址 0xC0000000 到 0xFFFFFFFF)由内核使用,称为内核空间 。而较低的 3G 字节(从虚拟地址 0x00000000 到 0xBFFFFFFF)由各个进程使用,称为用户空间 。

文章插图
为什么需要区分内核空间与用户空间?在 CPU 的所有指令中,有些指令是非常危险的,如果错用,将导致系统崩溃,比如清内存、设置时钟等 。如果允许所有的程序都可以使用这些指令,那么系统崩溃的概率将大大增加 。所以,CPU 将指令分为特权指令和非特权指令,对于那些危险的指令,只允许操作系统及其相关模块使用,普通应用程序只能使用那些不会造成灾难的指令 。区分内核空间和用户空间本质上是要提高操作系统的稳定性及可用性 。
2.1 内核态与用户态
当进程运行在内核空间时就处于内核态,而进程运行在用户空间时则处于用户态 。
在内核态下,进程运行在内核地址空间中,此时 CPU 可以执行任何指令 。运行的代码也不受任何的限制,可以自由地访问任何有效地址,也可以直接进行端口的访问 。
在用户态下,进程运行在用户地址空间中,被执行的代码要受到 CPU 的诸多检查,它们只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对任务状态段(TSS)中 I/O 许可位图(I/O Permission Bitmap)中规定的可访问端口进行直接访问 。
对于以前的 DOS 操作系统来说,是没有内核空间、用户空间以及内核态、用户态这些概念的 。可以认为所有的代码都是运行在内核态的,因而用户编写的应用程序代码可以很容易的让操作系统崩溃掉 。
推荐阅读
- 李沁|网传杨紫《青簪行》2023将播,男主真人补拍,还是AI换脸或虚拟人
- 虚拟光驱软件使用图文教程 虚拟光驱软件怎么用
- 虚拟机的作用知乎-虚拟机有什么好处和缺点?
- StampedLock:一个并发编程中非常重要的票据锁
- 女浩克|千呼万唤「超胆侠」终于登场!《女浩克》第7&8集彩蛋与细节分析!
- 虚拟内存能起到多大作用 电脑虚拟内存不足怎么办
- sd卡写保护了如何去掉? 手机内存卡被写保护
- 内存卡提示要格式化怎么办?
- 坐井观天的:进程 | 虚拟内存 | 虚拟地址
- 为什么不建议选512G内存手机?内行人给出了4个忠告,望周知
