Dll内存管理

15

我对Windows如何管理.dll文件的内存存在一些疑问。

  • 当.dll被加载到宿主进程中时,内存是如何管理的?

  • .dll是否可以访问宿主进程可用的所有内存,还是只能访问部分内存?也就是说,当函数在.dll内部分配内存时,是否存在限制?

  • 如果.dll使用STL类,例如string、vector(动态增加的存储等),会有问题吗?


相关问题:https://dev59.com/dnE95IYBdhLWcg3wi-ee - Björn Pollex
另一个相关的问题:https://dev59.com/-XI-5IYBdhLWcg3w3cnS - Björn Pollex
这个问题的被接受答案应该有你需要的东西:https://dev59.com/UUvSa4cB1Zd3GeqPf55A - Björn Pollex
这个问题:“当.dll文件被加载到主进程中时,内存是如何被管理的?”需要进一步澄清——你说“内存”时,指的是哪个实体? - Martin Ba
2个回答

9
“内存管理”通常是分别由操作系统和运行时负责的。操作系统将地址空间以大块交给运行时,然后由运行时以小块交给程序。这个地址空间可能已经分配了RAM,也可能没有(如果没有,则会有交换空间来支持)。
基本上,当加载DLL时,Windows会为代码和数据段分配地址空间,并调用DllMain()。C++编译器会安排从DllMain()中调用全局构造函数。如果它是用C++编写的DLL,它很可能依赖于一个C++运行时DLL,而这个DLL又依赖于Kernel32.DLL和User32.DLL。Windows理解这些依赖关系,并会安排它们以正确的顺序加载。
对于一个进程,只有一个地址空间,因此DLL将获得访问进程所有内存的权限。如果一个DLL在两个进程中加载,那么代码和数据将有两个逻辑副本,但是代码和只读数据的副本可能共享同一物理RAM。
如果DLL使用操作系统函数分配内存,Windows将为该过程从DLL进行的分配分配内存。该进程必须返回内存,但是该进程中的任何代码都可以这样做。如果您的DLL使用C++函数分配内存,那么它将通过在C++运行时DLL中调用operator new来执行此操作。必须通过在(相同的)C++运行时DLL中调用operator delete来返回该内存。同样,无论谁这样做都没问题。
vector<>这样的STL类可以被多次实例化,但只要使用相同的编译器就没有关系。所有的实例化都将是基本相等的,并且所有的实例化都会将向量的内存返回给相同的释放函数。
在这个解释中有两个主要的假设:
  1. 可执行文件及其DLL都是使用相同的编译器编译的。
  2. 可执行文件及其DLL都与C++运行时DLL链接(即不是静态链接)。
如果您想要发行一个单独的、自包含的可执行文件,则对C++运行时进行静态链接非常有用。但是,如果您已经在发行DLL,则应该将C++运行时保留在其自己的DLL中。

STL类如vector<>可以被多次实例化,但只要你使用相同的编译器,这并不重要。-- 还应该补充一点,不仅需要相同的编译器,还需要相同的标志,如果适用于这些:_SECURE_SCL等。 - Martin Ba

8

.dll是否可以访问主进程可用的所有内存或仅部分内存?即,当函数在.dll中分配内存时是否存在限制?

在DLL被加载到主进程后,对于“生活”在DLL中的代码与“生活”在原始可执行模块中的代码,没有任何区别。对于正在执行的进程,所有内存范围都是相同的,无论它们来自DLL还是来自原始可执行文件。

从DLL中获取的代码所能做的事情与编译在原始可执行模块中的代码所能做的事情没有区别。

话虽如此,在使用堆时确实存在差异-这些差异在Space_C0wb0y提供的评论中有解释。

像字符串、向量等STL类(动态增加存储)由.dll使用,这里会有问题吗?

如果在DLL的接口层使用它们,它们将会创建问题(可解决的问题,但仍然存在问题)。如果不在DLL接口层使用它们,则不会(或只在非常罕见的情况下)创建问题。我相信还有更多关于此的具体问题和答案。

基本上,如果在接口层使用它们,则必须使用“完全”相同的标志编译DLL和EXE,即类型需要二进制兼容。也就是说,如果您的DLL中的编译器标志(优化等)与EXE中的标志不同,以至于在EXE和DLL中内存中的std :: string不同,则在两者之间传递字符串对象将导致崩溃或静默错误(或从您的鼻子飞出的恶魔)。

如果仅在DLL内部函数之间或函数内部使用STL类型,则它们与EXE的兼容性并不重要。


如果你在DLL接口中使用它们,它们会创建问题(可解决的问题,但仍然存在)。你需要更多的解释或示例吗? - SysAdmin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接