WIN32的时空观 摘自<Delphi的原子世界>第三章,写的真好,只可惜不知道为什么没有把书写完,唉!
真是字字珠玑:
1. 在Windows下,同一程序可以同时有两个以上的副本在运行,每一个运行的程序副本就是一个进程。更确切地说,任何程序的一次运行就产生一个任务,而每个任务就是一个进程。一个典型的程序是由一个EXE文件或一个EXE文件加上若干DLL文件组成的静态代码和数据。
2. 进程是程序的一次运行,是在内存中动态运行的代码和动态变化的数据。当静态的程序要求运行时,操作系统将为本次运行提供一定的内存空间,把静态的程序代码和数据调入这些内存空间,将程序的代码和数据进行重定位映射之后,就在该空间内执行程序,这样就产生了动态的进程。同一个程序同时运行着的两个副本,意味着在系统内存中有两个进程空间,只不过它们的程序功能是一样的,但处于不同的动态变化的状态之中。
3. 进程分时调度的速度非常快,所以给我们的感觉就是进程都是同时运行的。其实,真正意义上的同时运行只有在多CPU的硬件环境中才有。真正推动进程运转的是线程,进程更重要的是提供了进程空间。
4. 每一个进程在自己独立的空间中运行。一个程序既包括代码空间又包括数据空间,代码和数据都要占据进程空间。Windows为每一进程所需的数据空间分配实际的内存,而对代码空间一般都采用共享手段,而数据空间是各自独立的。
5. WIN32的操作系统,如Windows 95和NT等,才是具备了真正的多进程和多任务操作系统的能力。WIN32中的进程完全由操作系统调度,一旦进程运行的时间片结束,不管进程是否还在处理数据,操作系统将主动切换到下一进程。WIN32实现了一种称为“抢占式多任务”的先进技术,其实只是纠正win16的缺陷而已。
6. 在WIN32操作系统中,各进程空间完全是独立的。WIN32为每一个进程提供一个可达4G的虚拟的,并且是连续的地址空间。
7. 在CPU窗口中的指令框中,你可以向上查看进程空间中的内容。当查看小于$00400000的空间内容时,你会发现小于$00400000的内容出现一串串的问号“????”,那是因为该地址空间还未映射到实际物理空间的缘故。如果在这时,你查看一下全局变量HInstance的16进制值就会发现它也是$00400000。虽然HInstance反映的是进程实例的句柄,其实,它就是程序被加载到内存中的起始地址值。因此,我们可以认为进程的程序是从$00400000开始加载的,也就是从4G虚拟空间中的4M以后的空间开始是程序加载的空间。
8. 从$00400000往后,到$0044D000之前,主要是程序代码和全局数据的地址空间。在CPU窗口中的堆栈框中,可以查看到当前堆栈的地址。同样,你会发现当前堆栈的地址空间是从$0067B000到$00680000的,长度为$5000。其实,进程最小的堆栈空间大小就是$5000,它是根据编译DELPHI程序时在ProjectOptions中Linker页中设置的Min stack size值,加上$1000而得到的。
9. 堆栈是由高端地址向底端增长的,当程序运行的堆栈不够时,系统将自动向地端地址方向增加堆栈空间的大小,这一过程将把更多的实际内存映射到进程空间。可在编译DELPHI程序时,通过设置ProjectOptions中Linker页中Max stack size的值,控制可增加的最大堆栈空间。
10. $80000000之后的2G空间是系统使用的空间。看来,进程能够真正拥有的只有2G空间。其实,进程能真正拥有的空间连2G都不够,因为从$00000000到$00400000的这4M空间也是禁区。
11. 从堆栈空间$400000之后到$80000000之间,是进程空间的主战场。进程从系统分配的内存空间将被映射到这块空间,进程加载的动态连接库将被映射到这块空间,新建线程的线程堆栈空间也将映射到这块空间,几乎所有涉及分配内存的操作都将映射到这块空间。请注意,这里所说的映射,意味着实际内存与这块虚拟空间的对应,没有映射为实际内存的进程空间是无法使用的,就象调试时CPU窗口指令框中的那一串串的“????”。