Virtualization

参考的技术博客
OSTEP slides
参考

虚拟内存

虚拟化:每个进程都认为,自己有自己的地址空间,多个进程的地址空间是分开的。 地址空间

实际上,CPU 拿到这些虚拟的地址,会让它内部的 MMU 把虚拟地址翻译成物理地址,也就是内存中的地址。内存里,每个地址可以存放一个字节。

分段

每个 segment对应地址空间里的logical entity, 比如stack/data。每个segment都可以:

  1. 单独放在内存的某个地方
  2. 拥有自己的protection bits
  3. grow and shrink

MMU为每个进程保持一个segment table. segment table 在虚拟地址中,top bits表示segment的序号,low bits表示segment内的offset。

虚拟地址0x0240对应的物理地址是多少?
这里有4个segment,所以用2位来表示segment序号。该地址二进制为00000000001001000000,前两位00是段号,即segment 0;后12位是偏移量。
因此它对应的物理地址是0x2000+0x240=0x2240

分段的缺点

会出现外部内存碎片。因为每个segment必须是整块出现的,如果一个segment过大,而内存中可能有多个小空间(碎片),却没有一个能放得下该segment的空间。

外部内存碎片是 OS 可见的。

分页

为了解决外部内存碎片的问题,分页方法把每个进程的地址空间切割成相同大小的page,放入内存中。内存中的每个可以容纳page 的单位,叫做 page frame, 页帧Alt text

页表

每个进程拥有一个页表。 里面记录着该进程的pages分别存放在哪个页帧。

一个页表有多大?

Linux中,一个page大小为4KB。假设系统为32位,那么一个进程的address space由32位表示,由于每一个address space可以保存一个byte,那么一个进程的address space大小为2^32=4GB.
4GB/4KB=2^20,即一个进程可以拥有2^20个page. 假设page table里面一项的数据大小为4KB,那么一个page table的大小为2^20*4KB=4MB.

page table 存储在内存中,MMU负责做翻译。 Alt text

分页的映射

在32位系统中,一个逻辑地址由20位虚拟页号+12位页内偏移量组成。

当某段数据不足一页大小,还是会被分成一个page,因此page内部存在内存碎片

主存作为虚拟内存的 cache

CPU交给 MMU 一个虚拟地址,MMU 去 page table里面,根据虚拟页号去找对应的物理页内存的基地址。找到了,则拿页内偏移量加上基地址,得到最终物理地址。
如果没有对应的物理地址,则是一个 cache miss, 即page fault exception
此时,kernel 里的 page fault handler首先判断DRAM是否已满,如果满了,会从 DRAM 里面驱逐一个page。随后OS把所需要的page从磁盘中加载到DRAM里。

当DRAM满时,这一过程也是swap out和swap in,即从DRAM选择其它进程没有在用的page,把它放到磁盘里去,而从磁盘里加载需要用的page到DRAM中。 cahce

当运行一个进程时,不需要把它address space里面所有的 page加载到DRAM中,而是用到哪些page,就加载哪些。

页表的缺点是:太大了,100个进程需要400M内存。

多级页表