Unix系统编程()虚拟内存管理

在之前学到过进程的内存布局中忽略了一个事实:这一布局存在于虚拟文件中。

因为对虚拟内存的理解将有助于后续对fork系统调用、共享内存和映射文件之类的主题阐述,这里还要学习一下有关虚拟内存的详细内容。

Linux像大多数现代内核一样,采用了虚拟内存管理技术。

该技术利用了大多数程序的一个典型特征,即访问局部性(locality of reference),以求高效使用CPU和RAM资源。

大多数程序都展现了这两种类型的局部性。

空间局部性(Spatial locality):是指程序倾向于访问在最近访问过的内存地址附近的内存(由于指令是顺序执行的,且有时会按顺序处理数据结构)。

时间的局部性(Temporal locality):是指程序倾向于在不久后的将来再次访问最近刚访问过的内存地址(由于循环)。

正是由于访问局部性特征,使得程序即便仅有部分地址空间存在于RAM中,依然可能得以执行。

虚拟内存的规划之一是将每个程序使用的内存切割成小型的、固定大小的"页"(page)单元。

相应的,将RAM划分成一系列与虚拟内存尺寸相同的页帧。

任一时刻,每个程序仅有部分页需要驻留在物理内存页帧中。

这些也构成了所谓驻留集(resident set)。

程序未使用的页拷贝保存在交换区(swap area)内——这是磁盘空间中的保留区域,作为计算机RAM的补充——仅在需要时才会载入物理内存。

若进程欲访问的页面目前并未驻留在物理内存中,将会发生页面错误(page fault),内核即刻挂起进程的执行,同时从磁盘中将该页面载入内存。

在不同的系统中页帧的大小不一样,一般常见的4096、8192和16384字节等。

为了支持这一组织方式,内核需要为每个进程维护一张页表(page table)。

该页表描述了每页在进程虚拟地址空间(virtual address space)中的位置(可为进程所用的所有虚拟内存页面的集合)。

页表中的每个条目要么指出一个虚拟页面在RAM中的所在位置,要么表明其当前驻留在磁盘上。

在进程虚拟地址空间中,并非所有的地址范围都都需要页表条目。

通常情况下,由于可能存在大段的虚拟地址空间并未投入使用,故而也无必要为其维护相应的页表条目。

若进程试图访问的地址并无页表条目与之对应,那么进程将收到一个SIGSEGV信号。

由于内核能够为进程分配和释放页(和页表条目),所以进程的有效虚拟地址范围在其生命周期中可以发生变化。

这可能发生于如下场景。

由于栈向下增长超出之前曾达到的位置。

当在堆中分配或释放内存时,通过调用brk、sbrk或malloc函数族来提升program break的位置。

当调用shmat连接System V共享内存区时,或当调用shmdt脱离共享内存区时。

当调用mmap创建内存映射时,或者调用munmap解除内存映射时。

image

虚拟内存的实现需要硬件中分页内存管理单元(PMMU)的支持。PMMU把要访问的每个虚拟内存地址转换成相应的物理内存地址,当特定虚拟内存地址所对应的页没有驻留于RAM中时,将以页面错误通知内核。

虚拟内存管理使进程的虚拟地址空间与RMA物理地址空间隔离开来,这带来许多优点。

原文地址:https://www.cnblogs.com/tuhooo/p/8667832.html