操作系统:内核相关术语
站内链接:
内核态,用户态,内核空间,用户空间
内核空间
地址范围:3G-4G, 0XC000 0000 ~ 0XFFFF FFFF
, 这是一个虚拟地址哦,大端和小端,实际映射到物理内存低地址, 在 32 位机上面,所有的进程内都是 4G 的虚拟地址,见程序员自我修养)
存放对象:内核代码,内核数据
用户空间
地址范围:0-3G
存放对象:用户代码,用户数据
附加:空间是一种内存的概念哦!
内核态
执行内核代码以及获取内核数据时所处的状态
用户态
在用户空间中进行操作时所处的状态称为用户态
内核态,用户态分级的意义
- 限权:限制不同程序的访问能力,防止非法获取其他程序的数据和外部设备的数据
- 内核态指令:访问内存中所有数据,外围设备,网卡(管控中心,CPU 资源-top 命令中的%sy)
- 用户态指令:只能访问自己的进程空间中的内存地址(CPU 资源-top 命令中的%us)
系统优化->产生管控中心概念->管控本身产生安全问题->限权
用户态切换,进程上下文切换
用户态之间的切换
用户进程通过”系统调用”进入内核态,具有一定的性能开销;
什么是上下文
context 就是当前 APP, 当前子程序, 当前子进程, 当前线程运行所依赖的基本配置, 基本数据等信息. 在不同的框架, 不同的语言生态中, 上下文还有各种细化的专业名词和分类, 例如 Javascript 环境中执行上下文
的分类:
- 全局执行上下文: 任何不在函数内部的代码都在全局上下文中, 比如 window 对象, 全局 this 指针
- 函数执行上下文: 实际上就上函数调用栈
- Eval 函数执行上下文
执行上下文
在几乎所有语言中都存在, 一个执行上下文实际上就是一个执行调用栈, Execution Context Stack
, 大部分情况下执行上下文中的数据和配置包含三个阶段:
- create: 进行初始化操作, 创建变量环境, 词法环境, 面向对象中 this 的指向等等.
- execute: 变量赋值, 代码执行
- gc-recovery: 出栈或者数据回收等
这里注意执行上下文和作用域的区别, 一般来说执行上下文的初始化会伴随着作用域的定义, 环境的初始化等, 执行上下文是一种更高层次的概念.
上下文切换
一个逻辑 CPU(并非物理 CPU)在同一时间运行一个线程,因为任务调度原因导致某一个线程一直不断的在多个 CPU 之间跳转,重复完成下面的任务:
- 软中断中止当前进程并保存 POS 值
- 将 CPU 中的各种 Register 值 PUSH 到进程私有内核栈中
- 在等待了一万年的时间之后,调度器再从私有栈中获取保存的数据到 Register 中,然后重新开干吧,向着社会主义!
线程,轻量级进程
类型
线程: 一个有线程 ID, 指令指针(PC), 寄存器集合, 堆栈组成.
内核线程:运行在内核态,不受用户态上下文的影响
用户线程:
1 | 说明: 运行在用户态,在用户空间中创建,不依赖系统核心,各个用户线程在当前所属进程内进行资源竞争. |
轻量级进程
1 | 说明: 一切都是为了弥补父辈的债,每一个轻量级进程对应一个调度对象(内核线程,可能多个). |
开销: 用户线程 lt 轻量级进程 lt 内核线程
内核线程和用户线程关系
都是从用户线程角度开眼看世界哦.
一对一模型:
1 | 说明: 每一个用户线程被绑定到一个单一的内核线程上 |
混合线程模型: 用户线程和内核线程的交叉,喂,大家各管各的,然后有货就交易,没货滚蛋!
多对一模型:多个用户线程映射到一个内核线程,线程之间的切换在用户态完成;
多对多模型:多个用户线程映射到几个内核线程中,自由的市场,自由的世界,自由的选择,自由的呼吸,
那么问题来了:
- 是否存在上下文切换的开销?一个 CPU 核心只跑一个上下文线程吧!
- 资源消耗的开销?(内存同步开销,切换开销,创建和消亡的开销,调度开销)
- 关键一点,你胜任多线程编写吗?各种 BUG
总结
在多核处理器中,一对一模型是最快的方式,当然,我们暂时抛弃先天硬伤!