1.进程各段在内存中的分布
在谈虚拟内存管理之前,我想先介绍一下进程在执行时各内存段(这里不做具体介绍,读者可自行了解)在X86体系下的分布情况:
内核映射到程序虚拟内存,但程序无法访问 |
---|
argv,environ |
栈 |
未分配的内存 |
堆 |
未初始化的数据(bss) |
初始化的数据 |
文本(程序代码) |
上图为我们形象的展示了进程各段在内存中的详细分布情况
2.虚拟内存管理
(1)概述
在前面的关于进程在内存中的布局,我们应明确的知道,这一布局都是存在与虚拟内存的,关于虚拟内存我们必须明确它不是真正的物理内存,而是实现对物理内存的一种管理机制,这种管理机制使得我们可以更加良好的利用内存
(2)产生的先决条件
虚拟内存管理技术利用了大多数程序基本特征(见下图),以求高效的使用CPU和RAM资源
程序访问局部性 | 具体表现 |
---|---|
空间局部性 | 是指程序趋向于访问在最近访问过的内存地址附近的内存 |
时间局部性 | 是指程序趋向于在不久的将来再次访问最近刚访问过的内存地址 |
(3)具体实施方案
由于访问局部性的特征,使得程序只有部分地址空间存在于RAM中,仍然可以运行
虚拟内存管理就是将程序所要使用的内存(此处为虚拟内存)切割成固定大小的的页,然后在RAM中也切割出和虚内内存相同的页,此处的页称为页帧。当程序运行时,程序只有一部分页(虚内内存)駐存到页(RAM)中,程序中暂时没用到的页则通过页拷贝存在了交换区(磁盘空间的保留区域,作为RAM的替代品),当程序运行一定时间,所要访问的页以在页帧中找不到时,程序就会发生页面错误,此时内核会将当前进程挂起,然后将先前保存在交换区中的页加载到RAM中,先前在RAM中的也或被删除或被替换
为了支持这种运作方式,内核必须要为每一个进程维护一张页表,页表中的每一项都描述了具体的一页在进程的虚拟地址空间中的位置,以及在RAM中的位置或在交换区中的位置
进程的虚拟地址空间所有页并非都要写到页表中,当页在短时间内都不会投入到RAM中使用时,我们也就没必要将此页维护在页表中
内核会生成一个页目录,其中会保存进程页表,然后将此页目录存在CPU附近的寄存器
由于内核可以为进程分配和释放页(和页表条目),所以进程的有效虚拟地址范围(和RAM相对应的地址范围)在其生命周期中可能发生变化具体可能会发生的场景如下:
由于栈所占用空间不断变大 |
---|
堆释放的内存的变化 |
共享内存区发生变化 |
创建或解除内存映射时 |
(4)虚拟内存管理的优点
1)适当情况下,进程之间可以共享内存,由于内核可以使不同的进程的页表指向同一RAM区域
2)便于实现内存保护机制,也就是说,可以对页表条目进行详细标记,以表示相关内容是可读可写
3)程序员编译器,链接器无须关注程序在RAM中的物理布局
4)因为要留在内存中的只是程序的一部分,所以程序加载和运行都会很快,而且一个进程所占的内存会相对变小,使内存可以同时处理跟多进程
(5)对虚拟内存本质的看法
之前也看过好多网上的好多人在讨论啥是虚拟内存,他们大概好像是说虚拟内存是交换区(见上文)
,我个人对虚拟内存的理解是,虚拟内存既不是RAM也不是交换区,它只是管理RAM的一种机制(概念),其中RAM是其管理的对象,而交换区只是其存储页的一个仓库(仅仅是仓库而已).