在Linux中,每个进程都有它自己的虚拟地址空间(例如32位系统中的4 GB,其中3GB是给进程使用的,1 GB是给内核使用的)。这种虚拟寻址机制有助于隔离每个进程的地址空间。对于进程而言,由于有很多进程,因此这是可以理解的。但既然我们只有一个内核,为什么我们还需要内核的虚拟寻址呢?
内核被称为“虚拟”的原因不是为了处理分页,而是因为处理器一次只能运行在一种模式下。所以一旦打开分页内存映射(x86上CR0中的第31位),处理器就期望所有内存访问都通过页面映射机制进行。因此,既然我们希望即使在启用分页(虚拟内存)后仍然可以访问内核,它就需要存在于虚拟空间中。
“保留”内存更多是出于“容易确定地址是内核还是用户空间”的考虑,而不是其他任何方面。完全有可能将内核的一小部分放在地址12345-34121处,将另一部分内核放在101900-102400处,将其他一部分内核放在40000000-40001000处。但这会让内核和用户空间的每个方面都变得困难 - 必须处理间隙/空洞[已经存在这样的空洞,但有更多也不会有所帮助]。通过设置一个固定的限制,即“用户空间从这里到这里,内核从用户空间的结尾到X”,在这方面使事情变得简单得多。我们可以在某些代码中只需写kernel = 0; if (address > max_userspace) kernel=1;
来区分内核和用户空间。
当然,内核只占用实际将使用的物理内存 - 因此普遍认为“占用整个千兆字节的内核是浪费”的想法是错误的 - 内核本身只占用几个(甚至对于非常“大”的内核也只有十几个)兆字节。加载的模块可以轻松地添加更多兆字节,而来自ATI和nVidia的图形驱动程序仅为内核模块本身增加了数兆字节。内核还使用一些内存位来存储“内核数据”,例如任务、队列、信号量、文件和其他内核必须处理的“东西”。同样需要几兆字节的内存。