《操作系统导论》虚拟化篇读书笔记
该笔记仅仅是我阅读时整理的一个脉络,具体详情还请观看本书
需要虚拟化什么
- 虚拟化CPU
- 虚拟化内存
如何虚拟化CPU
为什么需要虚拟化
给用户一种假象,你电脑有无数个CPU,可以同时运营无数个程序。
事实上,电脑并没有那么多,目前8核16核已经算很强了。
两种共享技术
时分共享:一个程序再不同的时间占用同一空间
空分共享:不同程序相同的时间占用不同的空间
引入进程
就是一种抽象,一个程序代码,如果运行起来,可以理解为一个进程
进程存在的问题
- 性能
- 控制权
解决控制权问题
受限直接执行
引入用户态与系统态
- 用户态:只对相应的资源有管理权限
- 系统态:对任何程序都有访问权限
如何操作
操作系统启动时,进入系统态,进行初始化,结束后进入用户态
用户态需要访问一些不具有权限的功能时,发起系统调用
通过硬件的一些机制,程序进入系统态,操作系统接管程序
操作系统完成一些操作,再次进入用户态
用户态程序继续运行
进程间上下文切换
进入系统态,操作系统接管,操作系统决定是切换进程还是继续进程运行,如果切换需要进行数据保护,该保存保存,避免信息丢失
不同进程之间的切换需要操作系统,某些流氓进程迟迟不发起系统调用,操作系统没有接管权限无法切换进程
通过硬件解决,假如时钟中断,每过一段时间,硬件时钟直接中断,程序进入系统态,操作系统接管,开始决定是否切换进程。
如果中断时又发生中断,并发问题怎么解决
放心,可以完美解决的,现在是虚拟化篇,别着急,后边还有并发
不同进程由操作系统切换,那操作系统如何确定由谁去运行呢
有好多进程调度算法,选择合适的
- FIFO
- SJF
- STCF
- 时间片轮转
- 多级反馈队列
需要考虑一个事情,假如一个进程调用了IO,接下来他不需要CPU资源了,这时候也发生切换,CPU又不怕996,不用给他放假的
一个很强悍的进程调度思路
通过随机数去调度进程,每个程序给一定的初始值,然后全部看随机数。
- 彩票机制
- 步长机制
缺点大大的,因为没研究好初始化怎么分配等等
内存虚拟化怎么说
为什么要虚拟化
给不同的程序一种假象,它自己独享一段从0开始的,连续的内存。
事实上,真实内存丑陋不堪。
我认为它还有一个好处,可以完美让高级语言得到运用,我不用担心我开发的程序运行在哪段内存,不用考虑我这个会不会跟别的冲突,操作系统已经帮我弄好了
物理地址与虚拟地址
物理地址就是真实的地址,直接对应硬件的。
虚拟地址就是给他一种假象之后的
物理地址怎么得到
通过初始地址+偏移量
一般用寄存器保存
动态重定位
物理地址与虚拟地址之间的转化,通过一定的硬件机制进行转换,直接能得出物理地址
能通过软件进行转化吗
是可以通过软件的,但是硬件跟软件比谁快自己猜。
有什么问题吗
程序一般分为代码区,栈,堆三部分。
如图所示,该程序我需要将基址寄存器的存入代码区最开始的那个位置。也就是初始地址在那个位置,偏移量为(栈最后的位置地址-初始位置地址),这时候中间有一段未使用的地址,其他程序想使用,但是你直接包含进去了,别的程序不知道你用没用,浪费严重
怎么解决
引入分段,我分为三个段,一个代码区,一个栈,一个堆。然后各自都有自己的初始地址跟偏移量,这下子中间就可以使用了
分段会产生碎片空间
也就是俩段之间有一丢丢空间没用,别人想用还用不了,因为太小
比如 ABC,B用完释放了,这时候来了个D,D比B空间发,放不进去,只能A空CD
可以进行合并
A 空 B C 空 D
可以整理成A B C D 空
合并特别浪费性能,有啥好办法吗
只能做到尽可能好。
分配空间的时候,采用一定的策略
- 最好匹配
- 最差匹配
- 首次匹配
- 下次匹配
各有优劣
分页机制
既然会产生碎片,我直接每次分配固定的大小,一个固定大小叫一页好了
这样不可能产生碎片。
分页的话地址转化起来比较慢的
引入缓存,也就是TLB
主要是局部性原理,缓存命中率还是很高的
如果TLB没有命中怎么办
RISC与CISC是不同的
一个是硬件的精简指令集,一个是复杂指令集
复杂指令集直接硬件帮你从内存找到然后写入TLB
精简指令集直接返回异常,然后你操作系统自己去操作TLB
上下文切换的时候TLB咋样
主要是进程A暂时不执行了,换B上场,如果用A的TLB会死人的
这时候可以切换的时候直接重置TLB,但是有点浪费资源
添加一个标号,属于谁的,你只能访问属于自己的TLB
TLB如果满了怎么替换
- LRU
- 随机
一个理论上好,但是需要消耗的资源特别大,一个简单。(感觉后边页面置换算法跟这个很类似,那个更多)
分页另一个问题,页表太大
因为分页是固定的,它有一个页表直接存着页起始地址的虚拟地址与物理地址的对应
但是假如32位的内存,一个页大小4k吧,2^20个页表项,然后一个页表项占用一定的内存,要死,太大了
解决思路
页大一点,页的总数就少一点,页表项小一点,表明了不好用,一个程序只用一丢丢内存,你直接分给一个页(很大)够跑十个它了,简直不可能
解决思路2
分页分段混用,其实可以想象,32位系统2^32个地址,4个G,谁家程序耗用内存这么大啊,而且每个程序都是这么大内存,摆明不可能,可以猜到大多数页是用不到的。
先分段,再对每个段提供一个页表
解决思路3
更常见的是,多级页表,先1级页表,对应个有些肯定没有的页表项,直接返回空,然后第二个。
举个例子,假如给河北省发10000张卡,然后我需要记录全河北省每个人对应的卡号(有些人没有也需要记录,至于为什么不卡号对应人而是非要人对应卡号那是反向页表的事,现在不考虑),明明只有10000张有用的记录,我非要记录全河北省几千万人。那么我可以分区,比如石家庄市,承德市,保定市等等,然后对于假如说石家庄市一个得到卡的都没有,那我直接石家庄返回没有,然后石家庄那么多人的记录直接变成了1个记录,节约大量内存。同理,保定市我还可以分成莲池区,竞秀区等等。
思路三有啥缺点吗
有一个问题,如果只有一级页表,我只需要访问内存1次就有结果,假如引入二级页表,我反问一级的页表得到是二级页表的位置,需要再次访问二级页表。访问两次内存肯定比一次要慢。
所以这里是时间换空间
提一下为啥不用反向页表
因为我用户经常是虚拟地址转化为物理地址比较多,我知道虚拟地址,页表如果使用哈希表(硬件机制实现)转化为物理地址很快,反过来就有点难搞了。这个其实算是时间换空间换到了极致,时间会很感人(或许后人可以解决这个麻烦)。
虚拟地址太大,物理地址根本没有那么大,程序就不能运行了吗
那不是,可以选择一部分外存当成内存使用(虚拟内存),当内存不够的时候,可以将相应的页表交换到该区域,把想用的交换到内存中
交换的时候采用什么策略
感觉这是要把内存当成外存的缓存来使用啊。
说到缓存不能不提TLB
但是这地方可用的就比TLB好多了
-
最优替换算法
这个算法只存在理论上,他想的特别美,预知未来要使用的页,换出不使用的。但是预知未来他咋想的那么美
所以这个算法基本上一直用来衡量其他算法好坏,越接近他越好
-
FIFO
-
随机
-
LRU
利用已知推算未来,已知这个最近用的很少,推测未来他也用的很少
可以说他特别接近最优替换
但是性能简直不堪啊,每次都要记录每个的使用时间,然后遍历一遍,这性能给他浪费的
由他演化的LFU差不多,都是根据已知推测未来
-
时钟页面置换算法
-
第二次机会法
后两种也是用历史信息推测未来,但是速度还快点,比较接近LRU的效果,但是速度比LRU快多了
总结
《操作系统导论》还是比较适合新手入门操作系统的一本书,深入浅出,但是知识点也比较详细,书中的知识比这个多多了,这里只是我梳理脉络整理的一个笔记。
我也是刚开始学,其中肯定有好多错误,希望大佬多多指正。