虚拟内存和内存保护

内存页表
1,在日常使用的Linux和Windows系统下,程序不能直接访问物理内存,内存通常分为固定大小的页,通过虚拟内存(Virtual Address)到物理内存(Physical Address)的映射,访问实际存储数据的物理内存位置。
2,建立映射页表,页表保存虚拟内存页号和物理内存页号的映射关系,将虚拟内存地址分为页号和偏移量,高位表示虚拟内存的页号,低位表示物理页号中的偏移量。地址转换步骤:
1)把虚拟内存地址,切分为页号和偏移量。
2)从页表里,查询虚拟页号,对应的物理页号。
3)取物理页号,加上偏移量,即得到物理内存地址。
3,同一页里的内存,在物理层面是连续的,以32位的内存地址为例,如果一个页是4K大小:
1)则需要12位的低位表示物理内存页的大小,即4K;
2)20位的高位表示页号,页表需要记录220个虚拟页号与物理页号的映射关系,页表里每个页号是32位,则页表大小为4MB;
3)每个进程都有独属的虚拟内存空间,都需要页表,光页表就需要占用很大的内存。

多级页表
1,大部分进程占用的物理内存是有限的,则需要的页也是有限的,不需要存下220个物理页表,只需要用到的页之间映射关系。
2,实践中,采用多级页表(Multi-Level Page Table)解决方案。
1)在实际进程里,虚拟内存通常占用两段连续的内存,不是完全散落的随机内存地址,多级页表适合这样的内存地址分布。
2)同样的虚拟内存地址,偏移量部分不变,原先页号部分拆分为四段,从高到低表4级到1级页表索引。
3,一个进程一张4级页表,可能多张3级、2级、1级页表,4级页表内存放3级页表地址,经此类推。
1)通过4级页表索引找到3级页表地址,通过3级页表地址和3级页表索引找到2级页表地址,以此类推找到最终物理页。
2)通过页号+偏移量获取最终的物理内存地址。
4,多级页表就像多叉树,可称为页表树(Page Table Tree)。以4级页表看,每级页表索引用5位表示,则每级页表只需要表示25=32项下一级页表地址,每项页表地址4个字节,一共需要128个字节。而一个一级索引表对应32个4KB即16KB的大小,一个填满的2级索引表,对应的32个1级索引表,即512KB的大小。
5,如果进程将1MB的内存空间分成2个512KB的连续空间,则需要两个独立填满的2级索引表,64个1级表,2个独立的3级索引表,1个4级索引表,一共需要69个索引表,每个索引表128字节,总需要9KB左右空间,比4MB节约了存储空间,但带来了时间的开销。
6,这是以时间换空间的策略,原本进行一次地址转换访问一次内存就能找到物理页号,算出物理内存地址,但用了4级页表,需要访问4次内存,才能找到物理页号。

加速地址转换:TLB
1,内存访问比Cache慢很多,多次地址转换则导致多次访问内存,程序指令顺序存放在虚拟内存里,顺序执行,内存地址连续,则指令通常在同一个虚拟页里,连续指令的内存地址转换,其实都是同一个虚拟页号,转换的结果自然也是同一个物理页号,增加一个缓存,将之前内存转换地址缓存下来,从而不需要反复访问内存进行地址转换。
2,在CPU里放一块缓存芯片TLB(Translation-Lookaside Buffer,地址变换高速缓冲),存放地址转换的结果,当需要地址转换的时候可直接在TLB里查询。
3,TLB和CPU高速缓存类似,分为指令TLB和数据TLB,即ITLB和DTLB,同样可以根据大小分成L1、L2多层的TLB。而且需要用脏标记位,实现写回的缓存管理策略。
4,在CPU芯片里面,封装了内存管理单元MMU(Memory Management Unit)芯片,用来完成地址转换,与TBL的访问和交互由MMU控制。

安全性和内存保护
1,实际程序指令的执行,通过程序计数器里的地址,读取内存里的内容,执行指令操作数据。
2,通过虚拟内存地址和物理内存地址的区分,隔离了每个进程,但在内存管理里,有一些最底层的内存安全保护机制。
1)可执行空间保护,对进程使用的内存,设置指令部分为可执行,数据部分无可执行权限,可控制进程内存空间的执行权限,CPU只能执行指令区域的代码,通过漏洞将数据区域的内容加载成指令,是没有执行的权限的。
2)地址空间布局随机化,进程内存布局空间固定的话,第三方很容易知道指令在哪,程序栈在哪,数据在哪,堆在哪,而内存空间布局随机化,随机地分配进程中不同部分的内存空间地址,位置不固定,第三方猜不到相应区域位置。
3,随机化策略还可以用在数据库保存用户名和密码中,在数据库中给每一个用户生成一个随机特殊字符串的盐值salt,将密码和盐值一起生成哈希值,哈希值中包括了乱码的随机字符串,则撞库无法猜出密码。

猜你喜欢

转载自blog.csdn.net/mei_true/article/details/127496083
今日推荐