DO(静态链接)的DLL使用不同的堆比主程序?(Do (statically linked) DLL

2019-06-25 00:20发布

我是新来的Windows编程和我刚刚“失去”两个小时狩猎,每个人都似乎觉察到的错误:你不能在一个DLL在堆上创建一个对象,并在另一个DLL摧毁它(或者在主程序) 。

我几乎可以肯定的是在Linux / Unix不是这种情况下(如果是,请说出来,但我敢肯定我做了上千次没有问题......)。

在这一点上我有几个问题:

1)不要静态链接使用不同的堆比主程序?

2)是在主程序的相同的进程空间中映射的静态链接DLL? (我确信这里的答案是YES大,否则就没有意义传递指针从一个函数在主程序功能的DLL)。

我说的是普通/常规DLL,而不是COM / ATL服务

编辑:由“静态链接”我的意思是我不使用LoadLibrary来加载DLL,但我与存根库链接

Answer 1:

的DLL / EXE文件将需要链接到的C运行时库的实现。

在çWindows运行时库的情况下,你必须指定的选项,如果你想链接到以下几点:

  1. 单线程C运行时库(支持单线程库已经现已停产)
  2. 多线程的DLL /多线程调试DLL
  3. 静态运行时库。
  4. 几个(您可以查看链接)

他们每个人将被提到一个不同的堆,所以你不能从一个运行时库的堆获得其它通地址。

现在,这取决于其C运行时库,你所谈论的已链接到DLL。 假设我们说,它使用的是已被链接到静态C运行时库DLL和应用程序代码(包含主功能)已链接到多线程C运行时DLL,然后如果你通过在分配的内存指针DLL来你的主要程序,并设法在那里解放出来,反之亦然,这会导致不确定的行为。 所以,基本的根本原因是C运行时库。 请慎重选择它们。

请找到支持的C运行时库的详细信息在这里和这里

从MSDN引述:

注意 不要混用运行时库的静态和动态版本。 有一个过程的运行时库的多个副本可能会导致问题,因为在一个副本的静态数据不与其他副本共享。 该连接器可以防止您使用一个.exe文件中的静态和动态链接的版本,但你仍然可以结束与运行时库的两个(或多个)副本。 例如,一个动态链接库与运行时库的静态(非DLL)版本的链接与与动态(DLL)链接的.exe文件时可能会导致问题的运行时库的版本。 (你也应该避免混合库的调试和非调试版本的一个过程。)



Answer 2:

让我们先来了解堆分配和堆在Windows操作系统WRT我们的应用程序/ DLL文件。 传统上,操作系统和运行时库来与堆的实现。

  1. 在一个进程的开始,操作系统创建一个名为进程堆一个默认堆。 过程堆用于如果没有使用其他堆中分配块。
  2. 语言运行时间也可以在进程内创建单独的堆。 (例如,C运行时创建它自己的堆。)
  3. 除了这些专用堆,应用程序或许多加载动态链接库(DLL),可以创建和使用单独的堆之一,被称为专用堆
  4. 这些堆坐落在所有虚拟内存系统操作系统的虚拟内存管理器的顶部。
  5. 让我们讨论更多关于CRT和相关堆:
    1. C / C ++运行时(CRT)分配器:提供malloc()和游离(),以及新的和删除操作符。
    2. 在CRT创造了其所有的分配这样一个额外的堆(此CRT堆的手柄内部存储在CRT库在全局变量称为_crtheap)作为其初始化的一部分。
    3. CRT创建自己的私有堆,驻留在Windows堆的顶部。
    4. 在Windows堆是围绕视窗运行时分配器(NTDLL)的薄层。
    5. Windows上运行时与分配虚拟内存分配器,其保留并承诺在操作系统中使用网页并进行互动。

你的DLL和EXE链接到多线程的静态CRT库。 每次创建DLL和EXE拥有自己的堆,即_crtheap。 在分配和去分配有来自相应的堆发生。 这从一个DLL动态分配的,不能从可执行的,反之亦然取消分配。

你可以做什么? 编译使用/ MD或/ MDD使用运行时库的多线程特异性和DLL版本我们的DLL和EXE文件的代码。 因此两个DLL和exe被链接到相同的C运行时库,因此一个_crtheap。 分配总是与一个单一模块中去分配配对。



Answer 3:

如果我有一个编译为一个.exe的应用程序,我想用一个库我可以静态地从一个的.lib文件链接库或动态链接该库从.dll文件。

每个链接模块(即每个.exe或.dll)将被链接到C的实现或C ++的运行时间。 运行时间本身,可以是静态或动态链接并有不同的线程配置的库。

静态链接 ,你描述的地方应用程序.exe动态链接到库的.dll和库内部静态链接到运行时设置? 我会认为这是你的意思。

另外值得一提的是,每一个模块(.exe或.dll),有它自己的范围为静态,即在一个.exe一个全局静态不会是同一个实例,在一个.dll同名的全局静态。

在一般情况下因此不能假定行代码运行的内部不同的模块使用相同的执行的运行时,而且它们将不使用任何的静态状态的相同实例进行。

因此,一定的规则需要的对象或跨模块边界指针打交道时,必须服从。 分配和释放必须发生对于任何给定的地址相同的模块中。 否则,堆将不匹配,行为不会被定义。

COM解决了这个这个使用引用计数,对象时,引用计数为零删除自己。 这是用于解决匹配位置问题的常见图案。

其他问题可以存在,例如Windows定义的某些动作,例如分配失败是如何在每个线程处理,而不是在每个模块的基础。 这意味着通过模块B上的螺纹设置在模块A中运行的代码也可以运行到意外行为。



文章来源: Do (statically linked) DLLs use a different heap than the main program?