关于dll的一些事以下是我自己对dll的一些疑问: 1.dll里面有个dllmain函数,那么在什么情况下依次进入以下四个分支? case DLL_PROCESS_ATTACH: 2.是否可以对同一个dll进行重复加载多次?那样做的效果是什么?即loadlibrary函数的特性 3.在不同进程里面加载的dll句柄handle是否相同? 4.加载到进程的dll什么时候被释放,是否可以对同一个dll释放多次? 5.dll里面的全局变量在什么时候初始化? 6.dll里面嵌套了其它dll时,加载和释放的顺序是什么。 7.dll里面循环嵌套(即A模块加载B模块的同时,B模块又会自动加载A模块)可以么?如果可以那么加载和释放的顺序是什么? 8.如果既可以对多个dll加载多次也可以对多个dll释放多次那么,两者的次数是否必须相等? 9.dll在第一个次使用它的时候加载到内存(动态加载的方式),那么在什么情况下从内存中彻底删除?
以下是本人亲测一下午的总结 注意:本次所有测试都是在win7平台vs2008上面测的,主要测试类型是动态加载的方式,没有涉及到静态加载时会是怎样的效果(太累了,眼睛花), 有兴趣的朋友可以自己测试一下。
case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: 答:在进程第一次加载dll的时候回进入DLL_PROCESS_ATTACH分支,有且仅有一次; 在进程正常结束或者明确使用FreeLibrary达到彻底引用减少到0的时候会进入case DLL_PROCESS_DETACH分支,有且仅有一次。 在进程或者当前进程加载的dll里面如果创建了新的线程,那么在该线程第一次得到cpu时钟的时候会进入所有dll的 case DLL_THREAD_ATTACH分支,由于可以 创建多个线程,因此可能有多次。 在线程函数执行完毕正常返回(即return或者exitthread)时会进入当前进程所加载的所有dll的 case DLL_THREAD_DETACH,有0次或者多次进入的可能。 2.是否可以对同一个dll进行重复加载多次?那样做的效果是什么?即loadlibrary函数的特性 答:完全可以用LoadLibrary多次加载同一个dll,实际上只有第一次是真正的加载,也会进入dllmain函数的DLL_PROCESS_ATTACH分支,后续使用LoadLibrary由于探测到进程地址空间中已经加载了该dll,因此只返回第一次加载成功的相同句柄,根本不会进入dllmain函数的DLL_PROCESS_ATTACH,因此后续只是对计数器加1。 3.在不同进程里面加载的dll句柄handle是否相同? 答:完全相同。 4.加载到进程的dll什么时候被释放,是否可以对同一个dll释放多次? 答:可以释放多次,每次都对引用计数减1,档计数为0的时候就从进程中卸掉该dll,此时会进入dllmain函数的 case DLL_PROCESS_DETACH:分支,并且 Freelibrary会在这次返回false,后面再继续调用Freelibrary也会返回false。 5.dll里面的全局变量在什么时候初始化? 答:dll里的全局变量在dll第一次加载到进程里面时初始化,早于dllmain函数的执行。 6.dll里面嵌套了其它dll时,加载和释放的顺序是什么? 答:如果明确用的Loadlibrary加载,那么顺序会严格按照LoadLibrary出现的顺序加载的。释放的顺序也是先加载谁就先释放谁。 7.dll里面循环嵌套(即A模块加载B模块的同时,B模块又会自动加载A模块)可以么?如果可以那么加载和释放的顺序是什么? 答:假设进程加载模块A.dll,A.dll里面在全局加载B.dll,也就是HMODULE hB=LoadLibraryA("B.dll")写在函数外面。同时B.dll里面又返回来加载A.dll,也是在全局写了如下的加载语句:HMODULE hA=LoadLibraryA("A.dll")这样就会导致循环加载A.dll时B会先初始化全局变量,从而执行HMODULE hB=LoadLibraryA("B.dll"),就会加载B,但是B又会初始化它自己的全局变量,导致HMODULE hA=LoadLibraryA("A.dll")被执行。这样就会导致循环加载,但实际上情况是这样的,加载顺序是A->B->A,只不过最后一次因为已经加载了所以不会重复加载,但进入dllmain函数的顺序是先进入B.dll的dllmain,然后再进入A.dll的dllmain。释放顺序先进入B.dll的dllmain然后再进入A.dll的dllmain,因为这个是真正的执行顺序。 另外,这种情况下DLL_THREAD_ATTACH:和DLL_THREAD_DETACH:的顺序进出的顺序是这样的:线程第一次切换时先进入A.dll的DLL_THREAD_ATTACH再进入B.dll的DLL_THREAD_ATTACH,线程函数运行完毕时先进入B.dll的DLL_THREAD_DETACH再进入A.dll的DLL_THREAD_DETACH。这和进程分支的情况正好相反。 8.如果既可以对多个dll加载多次也可以对多个dll释放多次那么,两者的次数是否必须相等? 答:可以不相等,但释放的次数必须大于等于加载的次数,否则不会真正卸载该dll,但会等待进程结束的时候释放。 9.dll在第一个次使用它的时候加载到内存(动态加载的方式),那么在什么情况下从内存中彻底删除? 答:多个进程可以引用同一个dll,每隔进程里面维护着对dll的引用计数,但进程内的引用计数只能用来决定是否从进程中卸载该dll。但dll真正是否能够从内存中删去,是靠另外一种计数N来维护的,那就是只要有一个进程加载了此dll且未卸载掉,那么N就会加1,一旦某个进程卸载掉了此dll,N就会减1,只有N减少到0的时候,操作系统才会从内存中将此dll测定删掉。 结语:相信有这些疑问的不止我一个人,希望能帮到同样有疑问的朋友,以上都是我亲自动手测试的,限于水品有限,若有错误请即刻指出,我会尽快修改,以免误导他人。 |
|