background image

在 C 和 C++语言开发中,指针、内存一直是学习的重点。因为 C 语言作为一种偏底层的中

 

低级语言,提供了大量的内存直接操作的方 法,这一方面使程序的灵活度最大化,同时
也为 bug 埋下很多隐患。
  因此,无论如何,我们都要对内存有一个清晰的理解。
 
  一、对内的分配
  32 位操作系统支持 4GB 内存的连续访问,但通常把内存分为两个 2GB 的空间,每
个进程在运行时最大可以使用 2GB 的私有内存(0x00000000—0x7FFFFFFF)。即理论上
支持如下的大数组:
 
char szBuffer[2*1024*1024*1024];
  当然,由于在实际运行时,程序还有代码段、临时变量段、动态内存申请等,实际上
是不可能用到上述那么大的数组的。
 
  至于高端的 2GB 内存地址(0x80000000—0xFFFFFFFF),操作系统一般内部保留使
用 , 即 供 操 作 系 统 内 核 代 码 使 用 。 在 Windows 和 Linux 平 台 上 , 一 些 动 态 链 接 库
(Windows 的 dll,Linux 的 so)以及 ocx 控件等,由于是跨进程服务的,因此一般也在高
2GB 内存空间运行。
 
  可以看到,每个进程都能看到自己的 2GB 内存以及系统的 2GB 内存,但是不同进程
之间是无法彼此看到对方的。当然,操作系统在底层做了很多工作,比如磁盘上的虚拟内
存交换(请看下以标题),不同的内存块动态映射等等。
 
  二、虚拟内存
  虚拟内存的基本思想是:用廉价但缓慢的磁盘来扩充快速却昂贵的内存。在一定时刻,
程序实际需要使用的虚拟内存区段的内容就被载入物理内存中。当物理内存中的数据有一
段时间未被使用,它们就可能被转移到硬盘中,节省下来的物理内存空间用于载入需要
使用的其他数据。
 
  在进程执行过程中,操作系统负责具体细节,使每个进程都以为自己拥有整个地址

空间的独家访问权。这个幻觉是通过 虚拟内存 实现的。所有进程共享机器的物理内存,
当内存使用完时就用磁盘保存数据。在进程运行时,数据在磁盘和内存之间来回移动。内
存管理硬件负责把虚拟地址翻译为物理地址,并让一个进程始终运行于系统的真正内存
中,应用程序员只看到虚拟地址,并不知道自己的进程在磁盘与内存之间来回切换。
 
  从潜在的可能性上说,与进程有关的所有内存都将被系统所使用,如果该进程可能
不会马上运行(可能它的优先级低,也可能是它处于睡眠状态),操作系统可以暂时取
回所有分配给它的物理内存资源,将该进程的所有相关信息都备份到磁盘上。
 
  进程只能操作位于物理内存中的页面。当进程引用一个不在物理内存中的页面时 ,
MMU 就会产生一个页错误。内存对此事做出响应,并判断该引用是否有效。如果无效,

内核向进程发出一个 segmentation violation

(段违规) 的信号,内核从磁盘取回该页,

——

换入内存中,一旦页面进入内存,进程便被解锁,可以重新运行

进程本身并不知道

它曾经因为页面换入事件等待了一会。