【问题标题】:Mixed mode assemblies loaded in all appdomains在所有 appdomains 中加载的混合模式程序集
【发布时间】:2014-07-07 13:34:36
【问题描述】:

我们的应用程序设置了一个 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 时,模块会立即加载到两个 AppDomains 中。

有谁知道为什么要在两个 AppDomain 中创建句柄?

【问题讨论】:

  • 好吧,不是这样。您将需要可用的 !gchandles 命令from the SOS debugger extension 来了解更多信息。
  • 谢谢,但是我不明白这对我有什么帮助。我已经知道我的手柄泄漏了。问题是为什么会发生这种情况,为什么在原始 AppDomain 和我为加载混合模式模块而创建的 AppDomain 中都设置了句柄。
  • 如果你不知道这个句柄是什么类型的对象,那么你就无法知道它是在哪里以及为什么被创建的。

标签: c# appdomain mixed-mode


【解决方案1】:

所以我对此进行了更多研究并找到了答案,所以我想如果有人遇到同样的问题,我会回答我自己的问题。

模块加载到两个 AppDomains 的原因是由于使用了本地全局值和静态成员值。这实际上是有道理的,因为这些值是在本机堆上分配的,并且如果在多个 AppDomain 中使用此模块,则很有可能您仍希望共享这些值。

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

为了解决这个问题,微软添加了__declspec(appdomain),它应该被添加到本地类型的全局变量中,这使得它们只驻留在创建模块的 AppDomain 中。打开/clr:pure 也将使其成为声明。大部分内容在 msdn's help on appdomain

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

【讨论】:

    猜你喜欢
    • 2015-08-03
    • 2015-06-09
    • 2011-06-20
    • 2010-12-14
    • 2011-03-20
    • 2011-03-11
    • 2023-04-09
    • 2012-12-28
    • 1970-01-01
    相关资源
    最近更新 更多