C# 多个AppDomain泄漏某些对象
我正在尝试创建一个插件系统。现在,我有一个系统可以在运行时加载和卸载一些动态库 我这样创建AppDomain:C# 多个AppDomain泄漏某些对象,c#,.net-3.5,appdomain,C#,.net 3.5,Appdomain,我正在尝试创建一个插件系统。现在,我有一个系统可以在运行时加载和卸载一些动态库 我这样创建AppDomain: AppDomain是一个private成员变量。 RemoteLoader是一个私有成员变量 AppDomainSetup setup = new AppDomainSetup { ApplicationName = assemblyName, ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, Co
AppDomain
是一个private
成员变量。
RemoteLoader
是一个私有成员变量
AppDomainSetup setup = new AppDomainSetup
{
ApplicationName = assemblyName,
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
};
AppDomain = AppDomain.CreateDomain(domainName, null, setup);
remoteLoader = (RemoteLoader)AppDomain.CreateInstanceAndUnwrap(assemblyName, typeName);
RemoteLoader
保留可用程序集的列表,可以创建对象和查找对象。
已正确创建AppDomain
。当我卸载时,我可以看到AppDomain
从VisualStudio上的模块列表中消失
我正在运行Jetbrains dotMemory查找内存泄漏
我现在的测试是:
- 加载服务,不带任何插件
- 快照
- 加载一些插件
- 让插件工作一段时间
- 卸载插件(卸载整个AppDomain)
- 快照
当我比较这两个快照时,我可以看到一些永远不会消失的对象
一些字符串
包含以下文本:
- STEP_Service.Contract.ModuleBase,STEP_Service.Contract,版本=1.0.0.0,区域性=中性,PublicKeyToken=null
- “/6ceffbca_d8b4_43be_39b8cb09ef37/s5bbue3ddey9xxfuevnmvmv9_158.rem”
- “c6360995_32bd_46d9_b83b_3fbac3c58c6a/w1ntjmpe4s+1zp1rkmrio_dy_141.rem”
我不知道发生了什么事。密钥保留路径向我显示:
[
堆栈跟踪:
一些RuntimeMethodInfo
正在泄漏:
其他对象,如:
卸载函数或任何位置都不会引发异常
我的Dispose
方法调用定义如下的Unload
:
/// <summary>
/// Unloads the plugins
/// </summary>
public void Unload()
{
if (AppDomain == null)
throw new NullReferenceException(nameof(AppDomain));
AppDomain.Unload(AppDomain);
remoteLoader.Dispose();
AppDomain = null;
remoteLoader = null;
}
//
///卸载插件
///
公众假期
{
if(AppDomain==null)
抛出新的NullReferenceException(nameof(AppDomain));
卸载(AppDomain);
remoteLoader.Dispose();
AppDomain=null;
remoteLoader=null;
}
我知道我没有提供太多的代码,但我真的不知道我需要给出什么样的代码。
如果丢失了什么,请向我索取
每个类
都是从MarshallByRefObject
派生的,为了测试,我将许多字段标记为不可序列化
根据我的概念,当我调用AppDomain类的static
方法Unload
时,必须释放AppDomain中的所有内容
编辑
在执行我的服务几分钟后,我可以看到以下对象:
看起来CrossAppDomainData和其他对象(由它自己持有)正在增长。该对象位于GC的第2代
编辑
一小时后,我可以看到2794个类型为CrossAppDomainData
的新对象,以及它所持有的一些其他对象
- 交叉应用域数据
- 交叉应用域接收器
- Int64
编辑
几个小时后,我可以看到大约32k个CrossAppDomainSink、CrossAppDomainData和Int64对象。我的服务内存从8k增长到17k
编辑
我发现了问题,但不知道为什么会发生这种情况。
为了发现问题,我逐步重新创建了服务。
当我多次加载/卸载appdomains时,一切都很好。所有内容都已正确释放,内存正常。
但是,在下一步,即在另一个应用程序上加载dll,以便具有卸载、更新和再次加载的功能时,出现了一些泄漏
换句话说,我的实际情况是:
- 在另一个AppDomain上加载核心DLL的服务
- 核心DLL可以在运行时加载插件
- 核心DLL可以在运行时更改
- FileSystemWatcher可以监视文件夹中CoreDLL上的更改。发生这种情况时,服务会在所有工作完成后卸载CoreDLL,加载新的CoreDLL,然后重新开始工作
加载的dll(CoreDLL)完成加载插件、查看插件文件夹等艰巨工作。该服务的存在只是为了让CoreDLL拥有自己的更新能力
那么…为什么前面提到的对象正在泄漏?调用是由CoreDLL进行的,而不是由服务进行的。mscorlib
始终是加载域中立的,这意味着所有应用程序域共享相同的mscorlib
。您的应用程序域确实使用了mscorlib
(因为它只是所有人的核心组件)。许多类型的mscorlib
都是可序列化的,因此对象将从您的自定义应用程序域封送到默认应用程序域。字符串的标识很弱-它们可以跨所有应用程序域直接访问。您是否有特殊问题或怀疑内存泄漏?@dymanoid我有内存泄漏。正如您在屏幕截图上看到的,t他会向我展示正在创建的字符串
和其他对象,如RuntimeMethodInfo
,ParameterInfo
。但当我运行第三个或更多快照并进行比较时,这些对象仍然存在。这些字符串是一些程序集名称和其他内容(在文章中我给出了一些示例)这本身不是内存泄漏。运行时总是会创建一些系统对象,如RuntimeMethodInfo
,并使其保持活动状态,而您无法控制这些对象。如果没有泄漏的用户对象,就没有内存泄漏。@dymanoid我明白了。但为什么我的内存会不断增加,即使dotMemory没有显示任何对象呢由我来处理?只是字符串、weakreference、crossappdomainsink不断增长。你有什么问题吗?你的内存不足吗?这些都是兆字节还是几千字节?GC不会尽快收集垃圾。它使用启发式和GC生成来确定何时收集。