在windows核心编程19.1中写道:  注意必须注意的是,单个地址空间是由一个可执行模块和若干个DLL模块组成的.这些模块中,有些可以链接到静态版本的c/c++运行期库,有些可以链接到一个DLL版本的c/c++运行期库,而有些模块(如果不是用c/c++编写的话)则根本不需要c/c++运行期库.许多开发人员经常会犯一个常见的错误,因为他们忘记了若干个c/c++运行期库可以存在于单个地址空间中.
VOID EXEFunc()

   PVOID pv = DLLFunc(); 
   //Access the storage pointed to by pv... 
   //Assumes that pv is in EXE's C/C++ run-time heap 
   free(pv);

 
PVOID DLLFunc()

   //Allocate block from DLL's C/C++ run-time heap 
   return(malloc(100)); 
}
如果EXE和DLL都链接到DLL的c/c++运行期库,那么上面的代码将能够很好地运行.但是,如果两个模块中的一个或者两个都链接到静态c/c++运行期库,那么对free函数的调用就会失败.我经常看到编程人员编写这样的代码,结果都失败了.问题:如果每个模块都是静态连接到运行期库,也就是说每个模块都有自己的已分配内存块记录.那么相应释放的也是自己模块内的内存,为什么会失败.
难道是“单个地址空间”?单地址上的内存地址相同,会按地址去释放别的模块的内存??

解决方案 »

  1.   

    看中文害死人,给你看英文的吧DLLs and a Process' Address Space
    It is often easier to create a DLL than to create an application because a DLL usually consists of a set of autonomous functions that any application can use. There is usually no support code for processing message loops or creating windows within DLLs. A DLL is simply a set of source code modules, with each module containing a set of functions that an application (executable file) or another DLL will call. After all the source code files have been compiled, they are linked by the linker just as an application's executable file would be. However, for a DLL you must specify the /DLL switch to the linker. This switch causes the linker to emit slightly different information into the resulting DLL file image so that the operating system loader recognizes the file image as a DLL rather than an application.Before an application (or another DLL) can call functions in a DLL, the DLL's file image must be mapped into the calling process' address space. You can do this using one of two methods: implicit load-time linking or explicit run-time linking. Implicit linking is discussed later in this chapter; explicit linking is discussed in Chapter 20, "DLL Advanced Techniques."Once a DLL's file image is mapped into the calling process' address space, the DLL's functions are available to all the threads running within the process. In fact, the DLL loses almost all of its identity as a DLL: To the threads in the process, the DLL's code and data simply look like additional code and data that happen to be in the process' address space. When a thread calls a DLL function, the DLL function looks at the thread's stack to retrieve its passed parameters and uses the thread's stack for any local variables that it needs. In addition, any objects created by code in the DLL's functions are owned by the calling thread or process—a DLL never owns anything.For example, if VirtualAlloc is called by a function in a DLL, the region of address space is reserved from the address space of the calling thread's process. If the DLL is later unmapped from the process' address space, the address space region remains reserved because the system does not keep track of the fact that a function in the DLL reserved the region. The reserved region is owned by the process and is freed only if a thread somehow calls the VirtualFree function or if the process terminates.As you know, the global and static variables of an executable file are not shared between multiple running instances of the same executable. Windows ensures this by using the copy-on-write mechanism discussed in Chapter 13, "Windows Memory Architecture." Global and static variables in a DLL are handled in exactly the same way. When one process maps a DLL image file into its address space, the system creates instances of the global and static data variables as well. Note  It is important to realize that a single address space consists of one executable module and several DLL modules. Some of these modules can link to a static version of the C/ C++ run-time library, some of these modules might link to a DLL version of the C/C++ run-time library, and some of these modules (if not written in C/C++) might not require the C/ C++ run-time library at all. Many developers make a common mistake because they forget that several C/C++ run-time libraries can be present in a single address space. Examine the following code:VOID EXEFunc() {
       PVOID pv = DLLFunc();
       // Access the storage pointed to by pv...
       // Assumes that pv is in EXE's C/C++ run-time heap
       free(pv);
    }PVOID DLLFunc() {
       // Allocate block from DLL's C/C++ run-time heap
       return(malloc(100));
    }So, what do you think? Does the preceding code work correctly? Is the block allocated by the DLL's function freed by the EXE's function? The answer is: maybe. The code shown does not give you enough information. If both the EXE and the DLL link to the DLL C/C++ run-time library, the code works just fine. However, if one or both of the modules link to the static C/C++ run-time library, the call to free fails. I have seen developers write code similar to this too many times, and it has burned them all.There is an easy fix for this problem. When a module offers a function that allocates memory, the module must also offer a function that frees memory. Let me rewrite the code just shown:VOID EXEFunc() {
       PVOID pv = DLLFunc();
       // Access the storage pointed to by pv...
       // Makes no assumptions about C/C++ run-time heap
       DLLFreeFunc(pv);
    }PVOID DLLFunc() {
       // Allocate block from DLL's C/C++ run-time heap
       PVOID pv = malloc(100);
       return(pv);
    }BOOL DLLFreeFunc(PVOID pv) {
       // Free block from DLL's C/C++ run-time heap
       return(free(pv));
    }This code is correct and will always work. When you write a module, don't forget that functions in other modules might not even be written in C/C++ and therefore might not use malloc and free for memory allocations. Be careful not to make these assumptions in your code. By the way, this same argument holds true for the C++ new and delete operators while calling malloc and free internally.
     
      

  2.   

    你要理解一个东西:静态链接的dll会把dll完全纳入exe中,dll不复存在,用这个方法来理解,就OK了。
    老实说,你问的这个问题要了解的东西非常的多才能解答,两言三语回答不清。
      

  3.   

    我是这样理解的,如果你用c/c++运行期库申请内存(dll中的方法申请),但是不掉用c/c++的运行期库释放内存(例如pb中的方法释放),就会出现问题。也就是说你的dll应该提供相应的释放函数。
      

  4.   

    2楼:“静态链接的dll会把dll完全纳入exe中,dll不复存在”
    那么就是dll在EXE中申请虚拟内存,然后在本模块释放,怎么会有问题呢?还是不懂啊!哈哈
      

  5.   

    malloc和free需要依靠本运行库管理内存
    如果模块(DLL和EXE)都是静态链接的运行库,则每个模块中都存在一个运行库
    这些运行库会在本模块LOAD的时候初始化
    并且本模块的malloc信息会记录在本模块的C运行库
    所以在本模块中malloc内存登记的信息在其他模块中是不识别的,free就会失败
      

  6.   


    听这位大哥的吧
    有一个补充,运行库在物理内存的每个副本(注意:是物理内存),system会给每个副本一个heap给本副本的malloc,free来使用。至于如何保证只能让本副本的这两个函数来使用,而另一个副本的free不能用于此副本的malloc,这个问题的答案,还是留给上面这位大哥吧