操作系统的核心是内核(kernel),它独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。
linux 内核空间在虚拟空间中是固定大小的,并且在物理空间中同样也是固定大小的。
一般情况下,内核空间会占用约1GB的内存,物理空间也会占用1GB的内存。
因此,在Linux系统下,如果有8GB的内存,实际上只有7GB可供进程使用。
如果是4G的虚拟空间:
虚拟地址0xC0000000到0xFFFFFFFF 供内核使用,称为内核空间
而较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF ,供各个进程使用,称为用户空间
内核后面还引入了高端内存概念。
内核空间中有了静态区域和动态区域。
Linux内核的高端内存概念是为了解决物理空间中内存不足的问题而引入的。
传统的内存管理方式中,内核空间的物理地址是连续的,因此内核只能访问固定大小的物理内存。
缺点:这会导致在安装了大量物理内存的系统上,内核只能使用其中一部分内存,从而造成资源的浪费。
2000年左右 Linux内核引入了高端内存的概念。
#需要注意的是,高端内存概念的引入和使用也需要硬件的支持。在一些旧的计算机或操作系统中,可能不支持高端内存的概念或无法完全利用高端内存的优势。
高端内存是指物理地址较高的内存区域,这部分内存区域在传统的内存管理方式中是无法被内核访问的。
通过将内核空间划分为静态区域和动态区域,高端内存可以被映射到内核空间中,使得内核可以访问更多的物理内存。
高端内存
静态区域占用约3~4G的内存地址空间
其中包含了内核代码、常量和静态变量等重要数据。
静态区域是内核空间的一部分,它的大小在编译时就已经确定,并且与用户空间是隔离的。
内核通过将静态区域映射到物理内存中,使得内核可以直接访问静态区域中的数据和代码。
内核通过页表(Page Table)来实现虚拟内存到物理内存的映射。
在系统启动时,内核会建立页表,将静态区域的虚拟地址映射到物理地址上。
这样,当内核访问静态区域时,实际上访问的是物理内存中的数据和代码。
所以,当用户态要访问静态区域中的数据时,实际上访问的是物理地址或物理功能,运行速度会明显的变慢。
内核函数vmalloc进行分配,特点是线性空间连续,但对应的物理空间不一定连续。
动态区域用于存储一些临时数据和缓冲区等,这些数据在系统运行过程中会频繁地创建和销毁。
例如:环境变量是在进程启动时由父进程传递给子进程的一组键值对,用于定义一些配置参数或路径。
这些环境变量可以在进程运行时被访问和修改,因此它们需要存储在动态分配的内存区域中,以便在进程生命周期内进行修改和更新。
注:在使用过程中需要注意避免出现内存碎片化的问题。同时,由于高端内存的使用需要经过内核空间的映射,因此在使用过程中需要注意避免出现越界访问等问题,以免造成系统崩溃或数据损坏等严重后果。
静态区域和动态区域的划分在内核编译时,就已经调整,需要调整内核的静态区域和动态区域需要重新编译内核。
内核总共能使用的物理空间就只有1G,这部分物理空间被划分为静态区域和动态区域。
栈和堆是动态分配的内存区域。
在动态区域里运行,它们的大小和位置在运行时可以动态地变化。
栈 用于存储局部变量和函数调用的信息,而 堆 用于动态分配和释放内存。
在 CPU 的所有指令中,有些指令是非常危险的,如果错用,将导致系统崩溃,比如清内存、设置时钟等。如果允许所有的程序都可以使用这些指令,那么系统崩溃的概率将大大增加。
所以,CPU 将指令分为特权指令和非特权指令,对于那些危险的指令,只允许操作系统及其相关模块使用,普通应用程序只能使用那些不会造成灾难的指令。
在内核态下,进程运行在内核地址空间中,此时 CPU 可以执行任何指令。运行的代码也不受任何的限制,可以自由地访问任何有效地址,也可以直接进行端口的访问。
在用户态下,进程运行在用户地址空间中,被执行的代码要受到 CPU 的诸多检查,它们只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对任务状态段(TSS)中 I/O 许可位图(I/O Permission Bitmap)中规定的可访问端口进行直接访问。
注:所有的系统资源管理都是在内核空间中完成的
系统调用、软中断和硬件中断
系统调用是程序请求内核执行某些操作,如文件读写、网络操作等。当程序发出系统调用时,会传递给内核所需的参数,然后进入内核空间执行相应的操作。系统调用完成后,内核会返回控制权给程序,继续执行后续的代码。系统调用的处理过程通常由操作系统实现提供的系统调用接口完成,这些接口提供了一组预定义的函数,用于与内核进行交互。
软中断是一种软件机制,用于处理一些可以被延迟到稍后执行的异步事件。当程序需要执行一些耗时操作时,可以使用软中断机制将部分工作交由内核处理,而程序本身可以继续执行其他任务。软中断的处理过程通常由操作系统的任务调度器负责,它会根据优先级和时间片等因素来决定何时执行哪些软中断。
硬件中断则是由硬件设备产生的信号,用于通知操作系统某个事件已经发生。例如,当用户按下键盘时,键盘控制器会产生一个中断信号,通知操作系统有一个键盘输入事件发生。硬件中断的处理过程通常由操作系统的中断处理程序负责,它会根据中断的类型和优先级来执行相应的处理函数。
运行于用户空间,执行用户进程。
运行于内核空间,处于进程上下文,代表某个特定的进程执行。
运行于内核空间,处于中断上下文,与任何进程无关,处理某个特定的中断。
当 CPU 空闲时,内核就运行一个空进程,处于进程上下文,但运行在内核空间。
linux中的top命令
第一项24.8 us(user 的缩写)就是 CPU 消耗在 User space 的时间百分比,
第二项0.5 sy(system 的缩写)是消耗在 Kernel space 的时间百分比。
ni:niceness 的缩写,CPU 消耗在 nice 进程(低优先级)的时间百分比
id:idle 的缩写,CPU 消耗在闲置进程的时间百分比,这个值越低,表示 CPU 越忙
wa:wait 的缩写,所有CPU 等待外部 I/O 的时间百分比,这段时间 等待I/O的CPU 不能干其他事,但是也没有执行运算,这个值太高就说明外部设备有问题
hi:hardware interrupt 的缩写,CPU 响应硬件中断请求的时间百分比
si:software interrupt 的缩写,CPU 响应软件中断请求的时间百分比
st:stole time 的缩写,该项指标只对虚拟机有效,表示分配给当前虚拟机的 CPU 时间之中,被同一台物理机上的其他虚拟机偷走的时间百分比
如果想查看单个程序的耗时,一般使用time命令。
real:程序从开始运行到结束的全部时间,这是用户能感知到的时间,包括 CPU 切换去执行其他任务的时间。
user:程序在 User space 执行的时间
sys:程序在 Kernel space 执行的时间
当进程请求一个I/O操作,它会执行一个系统(open() , read() , writer() , close())调用将控制权移交给内核。
1。用户程序发出系统调用请求,例如打开文件、写入文件或读取文件。这些系统调用会陷入内核态,由内核处理。
2。内核根据系统调用的类型,调用相应的文件系统代码。文件系统代码会解析文件路径,找到对应的文件或目录。
3。如果需要读取或写入文件,文件系统代码会与硬件驱动程序交互,将磁盘上的数据读入内存,或将内存中的数据写入磁盘。
4在数据读入内存后,内核会将数据复制到用户空间,以便用户程序可以访问这些数据。同样,当用户程序写入数据时,内核也会将数据从用户空间复制到内核空间,然后调用文件系统代码将数据写入磁盘。
5。如果用户程序请求查看文件属性或元数据(如文件大小、修改时间等),内核会调用文件系统代码来获取这些信息,并将其返回给用户程序。
6。在整个过程中,内核负责管理内存、处理器资源和其他系统资源,确保多个进程可以同时访问文件系统,而不会互相干扰。
7。内核还负责处理可能出现的错误和异常情况,例如文件不存在、磁盘空间不足等。在这些情况下,内核会返回相应的错误码给用户程序。
注:
内核中保存 了文件的inode信息,其中包括了文件的元数据和存储位置等重要信息。
文件路径是通过符号链接来组织的,这些符号链接通常保存在文件系统中。
文件的 inode在内核中保存 和 目录树存放在文件系统的一个位置,存储的真实数据位置放在后面排列。
1。用户程序通过系统调用访问文件,并传入文件路径作为参数。
2。内核接收到系统调用后,首先会检查文件路径的合法性,例如检查路径中是否存在非法字符、是否以斜杠结尾等。
3。内核根据文件路径中的目录和文件名,在文件系统中逐级查找。文件系统维护了一个目录树结构,其中每个目录节点都包含了子目录和文件的inode信息。
4。内核从根目录开始,逐级查找目录树,直到找到与文件路径匹配的目录节点。在查找过程中,内核会根据文件路径中的目录名和文件名,与目录节点中的信息进行匹配。
5。一旦找到匹配的目录节点,内核就可以获取该目录节点的inode号码。inode号码是文件系统中唯一标识一个文件的编号,通过inode号码可以找到文件的元数据和存储位置等信息。
6。内核使用inode号码在文件系统中找到对应的inode节点,获取文件的元数据和存储位置等信息。这些信息将被用于完成后续的文件访问操作。
注:目录树的大小要受到格式化时盘的大小限制。
目录树 :
/
/root /home /tmp /lib /dev /etc
硬盘通常不能直接访问用户空间
磁盘基于块存储的硬件设备操作的固定大小的数据块,用户进程请求的可能是任意大小或者非对齐的数据块,在这两者数据交互过程中内核负责数据的分解、再组合工作,起到一个中间人的角色。
分页区,即从物理内存置换出来,转而存储于磁盘上的内存页面.
把内存页大小设定为磁盘块大小的倍数,这样内核就可直接向磁盘控制硬件发布命令,把内存页写入磁盘,在需要时再重新装入。
所有磁盘 I/O 都在页层面完成。对于采用分页技术的,现代操作系统而言,这也是数据在磁盘与物理内存之间往来的唯一方式
Linux内核将内核空间分成了三个部分,分别是:ZONE_DMA 、 ZONE_NORMAL 、 ZONE_HIGHMEM。
内核空间名称 | 所占用位置 |
---|---|
ZONE_DMA | 内存开始的16MB空间 |
ZONE_NORMAL | 16MB-896MB |
ZONE_HIGHMEM | 896MB-结束(1G) |
当内核需要访问高于1G的内存空间的时候,例如内核需要访问0x50000000-0x500FFFFF这1MB内存空间的时候
只需要在ZONE_HIGHMEM这一个区域内临时申请一个1MB的内存空间,然后将其映射到上述需要访问的内存区域即可。
当内核使用完后,释放申请的1MB内存空间便完成对高于1G内存空间的访问了。