Linux (静态链接的)DLL 使用与主程序不同的堆吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10820114/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Do (statically linked) DLLs use a different heap than the main program?
提问by Emiliano
I'm new to Windows programming and I've just "lost" two hours hunting a bug which everyone seems aware of: you cannot create an object on the heap in a DLL and destroy it in another DLL (or in the main program).
我是 Windows 编程的新手,我刚刚“失去”了两个小时来寻找每个人似乎都知道的错误:您不能在 DLL 的堆上创建对象并在另一个 DLL(或主程序)中销毁它.
I'm almost sure that on Linux/Unix this is NOT the case (if it is, please say it, but I'm pretty sure I did that thousands of times without problems...).
我几乎可以肯定,在 Linux/Unix 上情况并非如此(如果是,请说出来,但我很确定我做了数千次没有问题......)。
At this point I have a couple of questions:
在这一点上,我有几个问题:
1) Do statically linked DLLs use a different heap than the main program?
1) 静态链接的 DLL 是否使用与主程序不同的堆?
2) Is the statically linked DLL mapped in the same process space of the main program? (I'm quite sure the answer here is a big YES otherwise it wouldn't make sense passing pointers from a function in the main program to a function in a DLL).
2)静态链接的DLL是否映射到主程序的同一个进程空间?(我很确定这里的答案是肯定的,否则将指针从主程序中的函数传递到 DLL 中的函数是没有意义的)。
I'm talking about plain/regular DLL, not COM/ATL services
我说的是普通/常规 DLL,而不是 COM/ATL 服务
EDIT: By "statically linked" I mean that I don't use LoadLibrary to load the DLL but I link with the stub library
编辑:通过“静态链接”我的意思是我不使用 LoadLibrary 来加载 DLL,但我与存根库链接
采纳答案by Jay
DLLs / exes will need to link to an implementation of C run time libraries.
DLL/exe 需要链接到 C 运行时库的实现。
In case of C Windows Runtime libraries, you have the option to specify, if you wish to link to the following:
对于 C Windows 运行时库,如果您希望链接到以下内容,您可以选择指定:
- Single-threaded C Run time library (Support for single threaded libraries have been discontinued now)
- Multi-threaded DLL / Multi-threaded Debug DLL
- Static Run time libraries.
- Few More (You can check the link)
- 单线程 C 运行时库(现已停止支持单线程库)
- 多线程 DLL / 多线程调试 DLL
- 静态运行时库。
- 更多(您可以查看链接)
Each one of them will be referring to a different heap, so you are not allowed pass address obtained from heap of one runtime library to other.
它们中的每一个都将引用不同的堆,因此不允许您将从一个运行时库的堆获得的地址传递给另一个。
Now, it depends on which C run time library the DLL which you are talking about has been linked to. Suppose let's say, the DLL which you are using has been linked to static C run time library and your application code (containing the main function) has linked to multi-threaded C Runtime DLL, then if you pass a pointer to memory allocated in the DLL to your main program and try to free it there or vice-versa, it can lead to undefined behaviour. So, the basic root cause are the C runtime libraries. Please choose them carefully.
现在,这取决于您所谈论的 DLL 已链接到哪个 C 运行时库。假设您使用的 DLL 已链接到静态 C 运行时库,并且您的应用程序代码(包含主函数)已链接到多线程 C 运行时 DLL,那么如果您传递一个指向分配在DLL 到您的主程序并尝试在那里释放它,反之亦然,这可能导致未定义的行为。因此,基本的根本原因是 C 运行时库。请仔细选择它们。
Please find more info on the C run time libraries supported here& here
A quote from MSDN:
引用自 MSDN:
CautionDo not mix static and dynamic versions of the run-time libraries. Having more than one copy of the run-time libraries in a process can cause problems, because static data in one copy is not shared with the other copy. The linker prevents you from linking with both static and dynamic versions within one .exe file, but you can still end up with two (or more) copies of the run-time libraries. For example, a dynamic-link library linked with the static (non-DLL) versions of the run-time libraries can cause problems when used with an .exe file that was linked with the dynamic (DLL) version of the run-time libraries. (You should also avoid mixing the debug and non-debug versions of the libraries in one process.)
注意不要混合使用静态和动态版本的运行时库。在一个进程中拥有多个运行时库副本可能会导致问题,因为一个副本中的静态数据不会与另一个副本共享。链接器阻止您在一个 .exe 文件中同时链接静态和动态版本,但您仍然可以得到两个(或更多)运行时库的副本。例如,与运行时库的静态(非 DLL)版本链接的动态链接库与与运行时库的动态 (DLL) 版本链接的 .exe 文件一起使用时可能会导致问题. (您还应该避免在一个进程中混合使用库的调试版本和非调试版本。)
回答by morechilli
If I have an application that compiles as an .exe and I want to use a library I can either statically link that library from a .lib file or dynamically linked that library from a .dll file.
如果我有一个编译为 .exe 的应用程序并且我想使用一个库,我可以从 .lib 文件静态链接该库或从 .dll 文件动态链接该库。
Each linked module (ie. each .exe or .dll) will be linked to an implementation of the C or C++ run times. The run times themselves are a library that can be statically or dynamically linked to and come in different threading configurations.
每个链接的模块(即每个 .exe 或 .dll)都将链接到 C 或 C++ 运行时的实现。运行时本身是一个库,可以静态或动态链接到不同的线程配置中。
By saying statically linked dllsare you describing a set up where an application .exe dynamically links to a library .dll and that library internally statically links to the runtime? I will assume that this is what you mean.
通过说静态链接的 dll,您是在描述应用程序 .exe 动态链接到库 .dll 并且该库在内部静态链接到运行时的设置吗?我会假设这就是你的意思。
Also worth noting is that every module (.exe or .dll) has its own scope for statics i.e. a global static in an .exe will not be the same instance as a global static with the same name in a .dll.
另外值得注意的是,每个模块(.exe 或 .dll)都有自己的静态范围,即 .exe 中的全局静态与 .dll 中具有相同名称的全局静态不是同一个实例。
In the general case therefore it cannot be assumed that lines of code running inside different modules are using the same implementation of the runtime, furthermore they will not be using the same instance of any static state.
因此,在一般情况下,不能假设在不同模块内运行的代码行使用相同的运行时实现,而且它们不会使用任何静态状态的相同实例。
Therefore certain rules need to be obeyed when dealing with objects or pointers that cross module boundaries. Allocations and deallocations must be occur in the same module for any given address. Otherwise the heaps will not match and behaviour will not be defined.
因此,在处理跨越模块边界的对象或指针时,需要遵守某些规则。对于任何给定地址,分配和解除分配必须发生在同一模块中。否则堆将不匹配并且行为将不被定义。
COM solves this this using reference counting, objects delete themselves when the reference count reaches zero. This is a common pattern used to solve the matched location problem.
COM 使用引用计数解决了这个问题,当引用计数达到零时,对象会删除自己。这是用于解决匹配位置问题的常见模式。
Other problems can exist, for instance windows defines certain actions e.g. how allocation failures are handled on a per thread basis, not on a per module basis. This means that code running in module A on a thread setup by module B can also run into unexpected behaviour.
可能存在其他问题,例如 windows 定义了某些操作,例如如何在每个线程的基础上而不是在每个模块的基础上处理分配失败。这意味着在模块 B 设置的线程上运行在模块 A 中的代码也可能遇到意外行为。
回答by Abhishek Jain
Let's first understand heap allocation and stack on Windows OS wrt our applications/DLLs. Traditionally, the operating system and run-time libraries come with an implementation of the heap.
让我们首先了解我们的应用程序/DLL 在 Windows 操作系统上的堆分配和堆栈。传统上,操作系统和运行时库都带有堆的实现。
- At the beginning of a process, the OS creates a default heap called Process heap. The Process heap is used for allocating blocks if no other heap is used.
- Language run times also can create separate heaps within a process. (For example, C run time creates a heap of its own.)
- Besides these dedicated heaps, the application program or one of the many loaded dynamic-link libraries (DLLs) may create and use separate heaps, called private heaps
- These heap sits on top of the operating system's Virtual Memory Manager in all virtual memory systems.
- Let's discuss more about CRT and associated heaps:
- C/C++ Run-time (CRT) allocator: Provides malloc() and free() as well as new and delete operators.
- The CRT creates such an extra heap for all its allocations (the handle of this CRT heap is stored internally in the CRT library in a global variable called _crtheap) as part of its initialization.
- CRT creates its own private heap, which resides on top of the Windows heap.
- The Windows heap is a thin layer surrounding the Windows run-time allocator(NTDLL).
- Windows run-time allocator interacts with Virtual Memory Allocator, which reserves and commits pages used by the OS.
- 在进程开始时,操作系统会创建一个称为进程堆的默认堆。如果没有使用其他堆,则进程堆用于分配块。
- 语言运行时还可以在进程内创建单独的堆。(例如,C 运行时会创建自己的堆。)
- 除了这些专用堆,应用程序或许多加载的动态链接库 (DLL) 之一可能会创建和使用单独的堆,称为私有堆
- 这些堆位于所有虚拟内存系统中操作系统的虚拟内存管理器之上。
- 让我们更多地讨论 CRT 和相关的堆:
- C/C++ 运行时 (CRT) 分配器:提供 malloc() 和 free() 以及 new 和 delete 运算符。
- CRT 为其所有分配创建这样一个额外的堆(此 CRT 堆的句柄内部存储在 CRT 库中名为 _crtheap 的全局变量中)作为其初始化的一部分。
- CRT 创建自己的私有堆,它位于 Windows 堆的顶部。
- Windows 堆是围绕 Windows 运行时分配器 (NTDLL) 的一个薄层。
- Windows 运行时分配器与虚拟内存分配器交互,后者保留并提交操作系统使用的页面。
Your DLL and exe link to multithreaded static CRT libraries. Each DLL and exe you create has a its own heap, i.e. _crtheap. The allocations and de-allocations has to happen from respective heap. That a dynamically allocated from DLL, cannot be de-allocated from executable and vice-versa.
您的 DLL 和 exe 链接到多线程静态 CRT 库。您创建的每个 DLL 和 exe 都有自己的堆,即 _crtheap。分配和取消分配必须从各自的堆中进行。从 DLL 动态分配的,不能从可执行文件中取消分配,反之亦然。
What you can do? Compile our code in DLL and exe's using /MD or /MDd to use the multithread-specific and DLL-specific version of the run-time library. Hence both DLL and exe are linked to the same C run time library and hence one _crtheap. Allocations are always paired with de-allocations within a single module.
你可以做什么?使用 /MD 或 /MDd 在 DLL 和 exe 中编译我们的代码,以使用多线程特定和 DLL 特定版本的运行时库。因此,DLL 和 exe 都链接到同一个 C 运行时库,因此链接到一个 _crtheap。分配总是与单个模块中的取消分配配对。