【笔记】什么是内核/用户空间 从CPU如何运行程序讲起

您所在的位置:网站首页 gameguardian虚拟空间应用程序 【笔记】什么是内核/用户空间 从CPU如何运行程序讲起

【笔记】什么是内核/用户空间 从CPU如何运行程序讲起

2024-07-03 18:50| 来源: 网络整理| 查看: 265

前言

本文从计算机是如何运行程序开始说起,说明什么是内核空间(kernel space)和用户空间(user space),以及两者区别;

Prerequisite 回到根本——计算机是如何运行程序的

参考我的这篇文章;

我们看到的程序是C、C++、JAVA这类高级语言,需要经过编译被转换为机器能够识别的01机器码,每条机器码都是很简单的指令,比如将两数相加、对两数作比较等,机器码的语言是硬性规定在CPU硬件中的,不可以随意改变。每种CPU(例如非常流行的Intel x86)都有属于自己的机器码,与其他CPU的机器代码不兼容。

程序其实就是一条条的基本指令和数据,静静存储在硬盘中,目前什么都干不了;

当需要运行程序的时候,硬盘中的程序就会被实例化到内存,也就是把程序的指令、数据都放到我们的RAM主存上(更具体的原理在这里就不细究了,属于OS的事情),这样CPU才能执行程序,这段程序也才变为了一个进程(当然也可以是多个进程); 在这里插入图片描述

进程与线程在本节开头的文章里有,不过对本文不是重点;

CPU以"取出/执行"的模式运行程序:

按顺序取出第一条指令;执行指令;继续取出下一条指令,往复循环;

当然有些指令,比如跳转(if、while就是通过跳转实现的),会影响其执行顺序;

在这里插入图片描述

操作系统(OS, Operating System)就像一个监管程序,在计算机启动时(“boots up”)开始运行,让用户浏览和运行程序。OS在后台组织所有程序的运行,给每个程序提供自己的内存区域,使其不干扰其他程序或整个系统(现代计算机基本就是采用前面介绍的虚拟地址空间技术);

虚拟地址空间、虚拟内存

现代处理器采用的是虚拟地址寻址的方式,也就是平时访问的内存地址其实都是虚拟地址,而虚拟地址又指向实际的物理地址,需要由操作系统和CPU硬件翻译成物理地址,才能访问该地址的值;

采用这种方式的原因:

如果应用程序可以直接访问物理内存,寻址物理内存的每一个细节,容易破坏操作系统;

再者,如果要运行多个进程,理想状态下是各个进程所占物理内存互不干扰,但谁也无法保证程序没有BUG,如果误操作到其他进程,就会导致程序出现运行问题;

当然也是有解决方案的,比如限定进程的内存访问界限,但这样会带来额外的寻址开销,这里不展开;

且不管进程间的内存干扰,每个进程都占据一部分内存,就会导致内存不足;

这里同样也有一些解决方案,比如手动覆盖技术、自动交换技术等,当然也同样存在各自的缺陷,这里也不细究;

那么为了解决上述问题,就有了虚拟内存技术,也成为了现代处理器内存寻址的解决方案;

虚拟内存地址空间被分成多个块,每块都有连续的地址空间,可以被分给应用程序;物理空间也同时被分成很多快,这些块大小和虚拟地址空间的块大小一致;系统会自动将虚拟地址空间映射到物理地址空间;进程只需要请求和操作虚拟内存,从每个进程的角度来看,内存中只存在操作系统内核以及本进程,自己独占了整个内存。

在这里插入图片描述

虚拟内存技术拥有自动覆盖技术和自动交换技术,使得能够运行比当前空闲内存空间还要大的程序,并借助外存获得更多的空闲内存空间;

再细说一下虚拟内存技术下CPU的寻址方式

倒也和本文不是那么相关,写在这篇博客下面了;

正文

正文算是对这篇文章的总结、简化和补充,有时间可以好好看看原文;

到底什么是内核空间

System memory in Linux can be divided into two distinct regions: kernel space and user space. Kernel space is where the kernel (i.e., the core of the operating system) executes (i.e., runs) and provides its services.”

– Kernel Space Definition, The Linux Information Project 2005.

这段引用也就很好的说明了,内核空间其实就是计算机内存的一部分,内核/用户空间是由操作系统划分的(实际的内存就还是一整块内存,没这种划分);

但是让我们继续深入,本文以UNIX家族来说明;

RAM中预留的空间

Prerequisite中我们已经讲了计算机运行程序的方式,OS将程序的指令加载进RAM,CPU再从RAM取指令……

但如果所有程序都能访问整块内存,包括其他程序和操作系统用到的那部分内存,就会大大提高系统故障率;那么作为监管者的OS就需要避免这种情况,同时优化内存的使用。

确实有技术可以让不同程序共享一块内存,但也不常见,我们不讨论共享内存的情况,要求不同程序间不应当共享内存。但不同程序还是会有一些必须共享的资源,比如显示器、网络连接、硬盘、打印机等,这些资源都会由OS进行保护和管理,这也正是OS的作用之一:管理所有的硬件并控制对他们的访问。这些属于OS的程序,如中断管理、进程调度、内存管理、硬件驱动等,都在RAM中属于OS的那部分,普通的用户进程是无法直接访问的,这部分属于OS的空间也就是所谓的Kernel space。

换句话说:内核空间就是OS划分的主内存的一部分,包含OS内核所有的指令。

在这里插入图片描述

注意到User Program1使用的内存有分块,这里简单做一下解释:

boot进程

现在我们有一台计算机,开机的时候都发生了什么?

由于处理器并没有多聪明,不可能自己知道我上电以后应该执行什么,所以必须得给处理器指定上电以后要干的第一件事情,然后逐步唤醒管家OS,点亮机器;

这部分我们先跳过吧

保护内核空间

MMU、虚拟内存空间、分页、页表、分段……这里不细究;总之就是保证了内核空间与用户空间的安全隔离;

访问内核空间

所以用户程序正常情况下是不能访问内核空间的,如果想访问内核空间,执行内核空间的指令,通常的方法就是使用系统调用(system call);

先说中断

处理器连接了很多外设,键盘、网卡、鼠标……可以用轮询的模式,不停的查看哪里有信号,但是就会浪费大量时间去轮询;

所以用的更多的模式是中断模式,每次键盘敲击、网卡收到数据包,都会发起中断,处理器就会保存当前状态到特定寄存器,以便处理完中断以后回来继续执行;随后处理器就会跳转到内核空间特定的内存地址,也就是“陷入内核态”,调用那个位置的异常处理程序,根据中断去做对应的处理。处理完以后就根据方才保存在寄存器中的状态继续做刚才的事情。

中断分硬中断和软中断,暂且理解为硬中断就是键盘、网卡这类硬件发出的电信号,软中断就是软件模拟硬中断的模式发出的中断信号。

系统调用

到这就不难理解系统调用了,我们可以把系统调用理解为一种软中断,当用户进程需要访问内核空间特定的资源时,就需要通过特殊的指令向处理器发起中断;处理器就会将该用户进程提供的信息填充到特定寄存器(太多的话就存到一块内存或者将这些信息入栈,不细究);

发起中断的参数取决于要在内核空间进行的行为,中断处理程序会根据传入的参数,采取适当的行动。

如果该进程的要求不合理的话,这适当的行动也可能是拒绝请求甚至关闭发起中断的进程(给出core dump警告,很熟悉吧)。比如说试图往未分配给该进程的内存地址写数据。

下图举例说明了syscall的整个过程,这其中也有一些混淆的概念。malloc()是C库的一个函数,封装了OS API的一个函数sbrk(),(没错,他俩都不算系统调用),实际的系统调用是封装在sbrk()里的sbrk系统调用,这会发起中断,之后“陷入内核态”,在内核空间执行对应的指令。

在这里插入图片描述

结语

自己的学习笔记和理解,难免有错误或补充还请指出,多多交流,感谢!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3