[英]Mixed mode assemblies loaded in all appdomains
我们的应用程序设置了一个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中。
有谁知道为什么要在两个AppDomain中都创建一个句柄?
因此,我进一步研究了这个问题并找到了答案,所以我认为如果有人遇到相同的问题,我会回答我自己的问题。
将模块同时加载到两个AppDomain中的原因是由于使用了本地全局值和静态成员值。 这实际上是有道理的,因为这些值是在本机堆上分配的,并且如果在多个AppDomain中使用此模块,则很有可能您仍然希望共享这些值。
问题是当您不断创建和销毁AppDomain并加载这些类型的资源时,因为首先添加到正在运行的进程AppDomain的引用是静态的,因此会导致固定。 这使托管堆碎片化,长时间运行的进程将开始消耗内存。
为了解决此问题,Microsoft添加了__declspec(appdomain)
,应将其添加到本机类型的全局变量中,以使它们仅驻留在创建模块的AppDomain中。 启用/clr:pure
也将使它成为声明。 msdn在appdomain的帮助中对此进行了详细说明
最后的陷阱是,您必须了解#include
文件。 例如, #include <string>
将导致模块在AppDomain之间共享,而#include <stdio.h>
则不会。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.