1、虚拟内存管理器:
windows提供了虚拟内存管理器,管理物理内存与硬盘之间的数据交换,以让应用程序运行时,只有必须的代码段和数据段进入物理内存,提高物理内存使用效率,并为并行程序提供运行环境。
理论上Win32虚拟内存管理器为每个Win32进程提供私有4GB大小的线性虚拟地址空间,按页来管理。进程在调用DLL时,这些DLL所用的内存空间是进程私有的,DLL中全部数据所用的内存都在该进程的虚拟地址空间上。虚拟内存管理器以4KB为页面大小处理内存,使用的是低区2GB空间,高区2GB留给系统使用。
我们经常看到的缺页错误是进程执行某段代码时或访问数据时,这些代码或数据没有在物理内存,系统会透明地将所需要的代码或数据置换进物理内存。
2、使用虚拟内存过程:
虚拟地址空间中的页有三种状态:自由、预留、提交。前两项没有涉及到真正的物理内存,后一项则是希望获取物理内存。提交只是从磁盘的调页文件中开辟空间,为置换物理内存做准备,直到进程代码第一次访问这段提交内存时,系统才分配内存,如果没有真正的物理内存,系统将报缺页错误,然后再分配物理内存。
对于线程而言,系统默认会分配1MB的预留虚拟地址区域,线程使用达到上限时,系统提交最后一页后抛出栈溢出异常,此时程序仍可正常运行,如果再需要空间,则会导致退出进程。为了防止这种空难,应该控制栈的使用大小,如减少嵌套调用、递归调用,不要定义大的局部变量(可在堆上申请大的空间),同时加上异常处理。
这种页面交换机制会造成指针、数组越界访问呈现不同的现象,有时程序直接崩溃,有时则不会。前者可能的情况是:指针、数组越界后的区域不在同一个页,而是一个没有提交的虚拟内存页,则会崩溃。后者是指针、数组越界后在同一个页或是其邻近页,则不会崩溃。
3、程序的效率:
因为频繁的调页操作引起的I/O会降低程序运行效率,因此虚拟内存管理器会将每个进程一定量的内存页驻留在物理内存中,这种内存页称为“工作集”,可由任务管理器中看到“工作集”是不断变动的。“工作集”常驻物理内存,不存在I/O,相对较快,如果执行的代码或访问的数据不在工作集中,则会引发额外的I/O,导致程序运行效率降低。一个极端的情况就是所谓的颠簸或抖动,程序大部分时间用在调页上。
为了提高效率,在编程中最好写紧凑代码,此处紧凑有两层含意:一是经常用到的代码放在一块。二是运算中使用效率高的运算符操作,如:前置单目运算符、复合运算符。对于数据,尽量将会同时访问的数据放到一起。