本文已参与「新人创作礼」活动,一起开启掘金创作之路。
内存的保护和性能的提升
如何提升性能
我们知道进程访问内存,都是通过虚拟地址到物理地址的转换才能实现。为了节省空间,我们采用多级页表来实现地址的转换。但是这样我们就需要访问4次内存才能找到物理地址,如果用4级页表的话。我们该如何将这个时间缩短,提升性能呢?
我们执行程序的指令,是一条条顺序执行的。也就是说,我们对指令地址的访问,存在时间局部性和空间局部性。那么很有可能连续多次转换的地址,都是在同一个物理页号。所以我们就可以加一个“缓存”把之前内存转换地址缓存下来,这样就大大减少了地址转换所需访问内存的次数。
我们在CPU里放了一块叫TLB(Translation-Lookaside Buffer,地址变换高速缓冲)的芯片。我们将已经地址转换过的查询结果存放在这里,当同样的虚拟地址需要进行地址转换的时候,我们就可以直接在TLB里面查询到结果了。
TLB类似于我们的Cache。同样也有指令TLB(ITLB)和数据TLB(DTLB),也有L1,L2的分级。还有就是,也需要用脏来标记数据,从而实现写回策略。
为了再次提升性能,整个内存地址转换的过程都交给硬件执行。这个硬件叫MMU(Memory Management Unit,内存管理单元)芯片,封装在CPU中。CPU,TLB和内存的交互,都由MMU控制。
安全性
进程的指令和数据都存放在内存里面。指令的执行,也是通过程序计数器里的地址,去内存读取内容,然后运行对应的指令,使用相应的数据。
所以这里的核心问题就是,第三方会获取和修改进程的指令、数据,然后造成破坏。那么如何来保证内存的安全性?
地址空间布局随机化
原来我们一个进程的内存布局空间是固定的,所以第三方很容易知道指令、数据、程序栈和堆在哪里。而地址空间布局随机化就是让这些位置不再固定
可执行空间保护
首先我们要知道,在CPU看来,指令和数据都只是二进制的数据而已。这样我们就完全可以将数据部分的编码改成指令部分的编码,再想办法让CPU把数据当成指令去加载,就可以随意执行我们想执行的指令了。
如何限制这种破坏呢?我们可以将指令部分设置成“可执行”权限,将其他部分,比如数据部分设置成“不可执行”权限。这样CPU就只能执行指令区域的代码了。这种办法就是可执行空间保护。