“《Delphi5 开发人员指南》第9章动态链接库”中的一段话没看懂,请帮忙解释一下!
{ }中的是原文。
{
9.1 究竟什么是DLL
D L L通过动态链接技术(dynamic linking)与其他应用程序共享代码,这将在本章后面部分讨论。总
之,当一个应用程序使用了一个D L L,Wi n 3 2系统会确保内存中只有一个该D L L的拷贝,这是通过内
存映射文件来实现的。D L L首先被调入Wi n 3 2的全局堆,然后映射到调用这个D L L进程的地址空间。
在Wi n 3 2系统中,每个进程都被分配有自己的3 2位线性地址空间。当一个D L L被多个进程调用时,每
个进程都会获得该D L L的一份映像。因此,在1 6位Wi n d o w s中,程序代码、数据、资源不被进程共享,
而在Wi n 3 2中,D L L是可以被看作是属于调用该D L L进程自己的代码。为得到关于Wi n 3 2概念的更多信
息,请参阅第3章“Win32 API”。
但这并不意味着,如果多进程调用一个D L L,物理内存就分配有该D L L的每个实例。通过从系统
的全局堆到调用该D L L的每一进程的地址空间的映射, D L L映像置于每个进程的地址空间。至少在理
想情况下应这样。
设置DLL的首选基地址
如果D L L被调入进程的地址空间时设置了基地址,这样D L L数据就可以被共享。如果D L L
的基地址与已经分配的D L L地址重叠的话,Wi n 3 2重新分配基地址。这样,每一个重新分配的
DLL实例都有自己的物理上的内存空间和交换文件空间。
这是很关键的,通过使用$ I M A G E B A S E指示符,给每个D L L都设置一个基地址,这样不
会引起冲突或不会出现地址重叠。
如果有多个应用程序都调用同一个D L L,设置一个唯一的基地址,这样无论是在进程的低
端地址或者是在一般的D L L (如V C L包)的高端地址,都不会引起冲突。一般可执行文件( E X E和
D L L )缺省的基地址为$ 4 0 0 0 0 0,这就意味着,除非修改D L L的基地址,否则就会与主程序的基
地址引起冲突,因此进程间也就不能共享DLL的数据。
在调用时,D L L不需要重新分配或安装,因为它保存在本地磁盘上,D L L的内存页面被直
接映射到磁盘上的D L L文件。D L L代码不需占用系统页面文件(也叫交换文件)的空间。这就是
为什么系统提交页的总数和大小可能比系统交换文件加内存要大。
}
我看完这段话感觉很糊涂、混乱、矛盾。
(一)“D L L首先被调入Wi n 3 2的全局堆”
--只是系统的dll被调入全局堆还是所有的程序自己的dll都被调入全局堆?(给10分)(二)“当一个D L L被多个进程调用时,每个进程都会获得该D L L的一份映像”
--是不是每个进程都获得了该dll的一份拷贝,都要占用一定的内存?我搞不清这个映像是指什么?(给10分)(三)“如果D L L被调入进程的地址空间时设置了基地址,这样D L L数据就可以被共享。如果D L L
的基地址与已经分配的D L L地址重叠的话,Wi n 3 2重新分配基地址。这样,每一个重新分配的
DLL实例都有自己的物理上的内存空间和交换文件空间。”
--妈的,这段话整个没看懂,什么乱七八糟的。是谁设置的基地址? 不设置基地址就不能实现dll共享吗?dll的地址怎么会发生重叠呢?如果dll地址没有发生重叠的话,dll实例能否得到物理的内存空间和交换文件空间?(给30分)(四)“这是很关键的,通过使用$ I M A G E B A S E指示符,给每个D L L都设置一个基地址,这样不
会引起冲突或不会出现地址重叠。
如果有多个应用程序都调用同一个D L L,设置一个唯一的基地址,这样无论是在进程的低
端地址或者是在一般的D L L (如V C L包)的高端地址,都不会引起冲突。一般可执行文件( E X E和
D L L )缺省的基地址为$ 4 0 0 0 0 0,这就意味着,除非修改D L L的基地址,否则就会与主程序的基
地址引起冲突,因此进程间也就不能共享DLL的数据。”
--妈的,这段话也整个没看懂,想问的写都写不出来,还是请整个详细解释吧!(给50分)

解决方案 »

  1.   

    对,了解一下操作系统是怎么管理内存的就能理解了。
    win95和win98以后的版本管理内存的区别。
      

  2.   

    建议楼主转贴到技术区。这个问题很好,完全有可能成为FAQ.不过放在这里句不合适了。
      

  3.   

    (一)
    只是系统的dll被调入全局堆,程序自己的dll当程序运行是被调入
    (二)
    不是每个进程都获得该dll的一份拷贝占用一定的内存, 假如有多个进程调用该DLL,在内存中只会存在一份该DLL的拷贝, 也就是说每个进程只是获得该DLL的入口地址指针.后面的不做解释了, 以免误导了,呵呵,祝好运了...
      

  4.   

    (一)任何Dll,只要被调饿内存,他就被放在全局堆上,而不论是系统还是程序自己的(二)实际上Dll的代码并不存在与为没个进程分配的2G的虚拟空间中。程序调用Dll的代码必将要知道Dll的地址,这种是方式的实现是通过Dll在系统全局堆的地址到进程自身空间地址的映射关系来实现的,具体的映射过程有操作系统来完成,如果你有兴趣可以去看看32位操作系统的书籍或资料(三)很简单,Dll被操作系统从自己实际处于的系统全局堆映射到进程自己的2G虚拟空间的时候,肯定第一个位置上的地址对应进程空间内的某个地址,这个地址就是Dll的基地址。如果这个地址处于已经分配的一个Dll的地址段内,那么这个地址将被重新分配。因为进程空间的地址与全局堆的地址虽然是通过映射来实现,但这种实现只能保证两个地址是一一对应的关系,而不可能是一对多!明白吗?举个简单例子:假如进程A需要调用两个Dll的函数,分别是B和C这两个Dll,那么当把B映射到自己的进程空间时假设地址段是50到80,这里的50就上B的基地址,这个时候,如果把C也映射进来,如果你把C的基地址定为60是肯定不可以的,因为60这个地址已经被B占据了,所以系统会重新进行分配,有可能是81。明白?(四)我们知道在32位的操作系统中,系统会为每个进程分配2G的虚地址空间,但实际上每个进程是根本使用不了这么多的空间的,连1G都不能用到,从最低端地址到$400000这里是被系统占据的。程序的代码和数据都是从$400000开始被调入存放的!从这里开始的进程虚地址空间的存放内容和顺序都是基本相同的(对任何进程而言)。所以我们必须使用编译指令$IMAGEBASE来为Dll指定一个调入起始地址(即基地址),其实说白了就是调到一个不毛之地,否则就会发生地址冲突。但发生冲突后系统是否会象上面那样自动重新调整偶就不清楚了,忘记了,你找找相关资料看看吧!呵呵....