在所有应用域中加载的混合模式程序集

本文关键字:混合 模式 程序集 加载 应用 | 更新日期: 2023-09-27 18:12:00

我们的应用程序设置了一个AppDomain,我们将一些模块加载到其中。其中一个模块是使用遗留的混合模式DLL与h5文件进行交互。问题是,一旦加载了混合模式DLL,就会在新的AppDomain和应用程序启动时创建的原始AppDomain中放置一个句柄。

当我们卸载AppDomain时,新AppDomain中的句柄自然消失,但原AppDomain中的句柄仍然存在并被固定。这将导致托管堆的碎片化。

我在混合模式源代码中找不到任何可以解释这种行为的东西。唯一可疑的地方是下面这个调用,它使用了一个本地静态字符串:

H5Utils::throwError( String^ message ) {
  String^ stackStr = gcnew String( H5Utils::errorStack_.c_str() );
  String^ myMessage = message + "'n'nError stack: " + stackStr;
  throw gcnew H5IOError( myMessage );
}

,其中H5Utils::errorStack_.c_str()为本机静态字符串。但是这个方法永远不会被调用,并且当混合模式DLL被加载时,模块会立即加载到两个appdomain中。

有谁知道为什么一个句柄会在两个AppDomains创建?

在所有应用域中加载的混合模式程序集

所以我深入研究了一下,找到了一个答案,所以我想如果有人遇到同样的问题,我可以回答我自己的问题。

模块被加载到两个appdomain的原因是由于使用了本地全局值和静态成员值。这实际上是有意义的,因为这些值是在本机堆上分配的,如果这个模块在多个AppDomain中使用,那么您仍然希望共享这些值的可能性很大。

问题是当你不断地创建和销毁AppDomain并加载这些类型的资源时,因为首先添加到运行进程AppDomain的引用是静态的,因此会导致固定。这使得托管堆碎片化,长时间运行的进程将开始消耗内存。

为了解决这个问题,Microsoft添加了__declspec(appdomain),它应该添加到本机类型的全局变量中,这使得它们只驻留在创建模块的AppDomain中。打开/clr:pure也会使此声明生效。中描述了其中的大部分内容Msdn关于appdomain的帮助

最后一个问题是,您必须知道您的#include文件。例如,#include <string>将导致模块在appdomain之间共享,而#include <stdio.h>则不会。