本文以32位系统为例介绍内核空间(kernelspace)和用户空间(userspace)。
内核空间和用户空间对32位操作系统而言,它的主存空间(虚拟地址空间,或叫线性地址空间)为4G(2的32次方)。也就是说一个进程的最大地址空间为4G。
操作系统的核心是内核(kernel)linux 内核 用户空间,它独立于普通的应用程序,可以访问受保护的显存空间,也有访问底层硬件设备的所有权限。为了保证内核的安全,现今的操作系统通常都强制用户进程不能直接操作内核。
具体的实现方法基本都是由操作系统将虚拟地址空间界定为两部份,一部份为内核空间,另一部份为用户空间。针对Linux操作系统而言,最高的1G字节(从虚拟地址0xCxC0000000到0xFFFFFFFF)由内核使用,称为内核空间。而较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF)由各个进程使用,称为用户空间。
对前面这段内容我们可以这样理解:「每个进程的4G地址空间中,最高1G都是一样的,即内核空间。只有剩余的3G才归进程自己使用。」
「换句话说就是,最高1G的内核空间是被所有进程共享的!」下图描述了每位进程4G地址空间的分配情况(此图来自互联网):
为何须要分辨内核空间与用户空间在CPU的所有指令中,有些指令是十分危险的,假如错用,将造成系统崩溃红联linux论坛,例如清显存、设置时钟等。假如容许所有的程序都可以使用这种指令,这么系统崩溃的机率将大大降低。
所以,CPU将指令分为特权指令和非特权指令,对于这些危险的指令,只容许操作系统及其相关模块使用,普通应用程序只能使用这些不会引起灾难的指令。
例如Intel的CPU将特权等级分为4个级别:Ring0~Ring3。虽然Linux系统只使用了Ring0和Ring3两个运行级别(Windows系统也是一样的)。
当进程运行在Ring3级别时被称为运行在用户态,而运行在Ring0级别时被称为运行在内核态。
内核态与用户态好了我们如今须要再解释一下哪些是内核态、用户态:「当进程运行在内核空间时就处于内核态,而进程运行在用户空间时则处于用户态。」
在内核态下,进程运行在内核地址空间中,此时CPU可以执行任何指令。运行的代码也不受任何的限制,可以自由地访问任何有效地址,也可以直接进行端口的访问。
在用户态下,进程运行在用户地址空间中,被执行的代码要遭到CPU的众多检测,它们只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对任务状态段(TSS)中I/O许可位图(I/OPermissionBitmap)中规定的可访问端口进行直接访问。
对于先前的DOS操作系统来说,是没有内核空间、用户空间以及内核态、用户态这种概念的。可以觉得所有的代码都是运行在内核态的,因此用户编撰的应用程序代码可以很容易的让操作系统崩溃掉。
对于Linux来说,通过分辨内核空间和用户空间的设计,隔离了操作系统代码(操作系统的代码要比应用程序的代码强壮好多)与应用程序代码。
虽然是单个应用程序出现错误也不会影响到操作系统的稳定性,这样其它的程序还可以正常的运行(Linux而且个多任务系统啊!)。
「所以,分辨内核空间和用户空间本质上是要提升操作系统的稳定性及可用性。」
怎样从用户空间步入内核空间虽然所有的系统资源管理都是在内核空间中完成的。例如读写c盘文件,分配回收显存雨林木风linux,从网路插口读写数据等等。
我们的应用程序是难以直接进行这样的操作的。并且我们可以通过内核提供的插口来完成这样的任务。
例如应用程序要读取c盘上的一个文件,它可以向内核发起一个“系统调用”告诉内核:“我要读取c盘上的某甲文件”。
虽然就是通过一个特殊的指令让进程从用户态步入到内核态(到了内核空间),在内核空间中,CPU可以执行任何的指令,其实也包括从c盘上读取数据。具体过程是先把数据读取到内核空间中,之后再把数据拷贝到用户空间并从内核态切换到用户态。
此时应用程序早已从系统调用中返回而且领到了想要的数据,可以开开心心的往下执行了。简单说就是应用程序把高科技的事情(从c盘读取文件)外包给了系统内核,系统内核做这种事情既专业又高效。
对于一个进程来讲,从用户空间步入内核空间并最终返回到用户空间,这个过程是非常复杂的。举个反例,例如我们常常接触的概念“堆栈”,虽然进程在内核态和用户态各有一个堆栈。
运行在用户空间时进程使用的是用户空间中的堆栈,而运行在内核空间时,进程使用的是内核空间中的堆栈。所以说,Linux中每位进程有两个栈,分别用于用户态和内核态。
右图简明的描述了用户态与内核态之间的转换:
既然用户态的进程必须切换成内核态能够使用系统的资源,这么我们接出来就瞧瞧进程一共有多少种方法可以从用户态步入到内核态。
概括的说,有三种方法:系统调用、软中断和硬件中断。这三种形式每一种都涉及到大量的操作系统知识,所以这儿不做展开。
整体结构接出来我们从内核空间和用户空间的角度看一看整个Linux系统的结构。它大体可以分为三个部份,从下往上依次为:硬件-》内核空间-》用户空间。如右图所示(此图来自互联网):
在硬件之上,内核空间中的代码控制了硬件资源的使用权,用户空间中的代码只有通过内核曝露的系统调用插口(SystemCallInterface)能够使用到系统中的硬件资源。虽然,不光是Linuxlinux 内核 用户空间,Windows操作系统的设计也是晋中小异。
实际上我们可以将每位处理器在任何指定时间点上的活动概括为下述两者之一:
运行于用户空间,执行用户进程。
运行于内核空间,处于进程上下文,代表某个特定的进程执行。
运行于内核空间,处于中断上下文,与任何进程无关,处理某个特定的中断。
以上三点几乎包括所有的情况,例如当CPU空闲时,内核就运行一个空进程,处于进程上下文,但运行在内核空间。
说明:Linux系统的中断服务程序不在进程的上下文中执行,它们在一个与所有进程都无关的、专门的中断上下文中执行。
之所以存在一个专门的执行环境,就是为了保证中断服务程序才能在第一时间响应和处理中断恳求,之后快速地退出。
总结现代的操作系统大都通过内核空间和用户空间的设计来保护操作系统自身的安全性和稳定性。所以在我们阅读有关操作系统的资料时常常遇见内核空间、用户空间和内核态、用户态等概念,希望本文才能帮助您理解这种基本的概念。