C# 将程序集加载到AppDomain中,但也加载到AppDomain.CurrentDomain中,从而导致内存泄漏
我必须执行从jscript到另一个appdomain而不是当前appdomain的某行。为此,我有以下代码C# 将程序集加载到AppDomain中,但也加载到AppDomain.CurrentDomain中,从而导致内存泄漏,c#,reflection,console-application,appdomain,C#,Reflection,Console Application,Appdomain,我必须执行从jscript到另一个appdomain而不是当前appdomain的某行。为此,我有以下代码 AppDomain ad = null; try { ad = AppDomain.CreateDomain("new AD" + new Random(), null, null); ad.CreateInstanceAndUnwrap ( assembly, type, t
AppDomain ad = null;
try
{
ad = AppDomain.CreateDomain("new AD" + new Random(), null, null);
ad.CreateInstanceAndUnwrap
(
assembly,
type,
true,
BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance,
null,
args,
null,
null,
null
);
}
catch (Exception e)
{
throw new Exception("Automated script engine had an error. " + e.Message + "\n" + e.InnerException.StackTrace + "\n" + e.HelpLink);
}
finally
{
if (ad != null)
{
Assembly[] a = ad.GetAssemblies();
Console.WriteLine(a.Length);
Assembly[] mainAssemblies = AppDomain.CurrentDomain.GetAssemblies();
Console.WriteLine(mainAssemblies.Length);
AppDomain.Unload(ad);
GC.AddMemoryPressure(GC.GetTotalMemory(true));
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.Collect();
ad = null;
}
}
}
但是,当我检查加载到当前AppDomain中的所有程序集时(通过AppDomain.CurrentDomain.GetAssemblys()
),我的asembly也会加载
由于我可能必须运行2000测试
,我知道2000程序集
将加载到我的CurrentDomain
是否有方法将此程序集加载到AppDomain,但不将其添加到CurrentDomain
finally
块中的方法调用只是我在这里的尝试。如果它们没有用处,请不要对我进行评判。IIRC在.NET 2.0中无法卸载程序集,但如果在以后的版本中可能,请纠正我,我没有检查过。所以,确保这是可能的,因为从前卸货是不可能的
第二,需要2000个不同的文件才能有2000个不同的程序集。也许你的意思是加载相同的组件2000次?在这种情况下,内存中实际上只有一个程序集
有一种方法可以只将反射数据加载到内存中,而不实际加载程序集,但这不是您想要的
GC在这里帮不了什么忙。查看测试驱动开发以获取更多的指针…首先,您必须了解,当程序集加载到appdomain中时,您无法卸载任何程序集 要确保程序集未加载到您的
main
app域中,您需要远程处理。
这意味着您的类型
必须派生自MarshalByRefObject
,并且必须是可序列化的
GC
不负责卸载或加载任何程序集。垃圾收集器确保对托管内存进行memory清理。泄漏的罪魁祸首是:
Assembly[] a = ad.GetAssemblies();
在不加载程序集的情况下,无法将程序集从一个AppDomain传递到另一个AppDomain。因此,尽管您最初已将程序集加载到“ad”中,但调用AppDomain.GetAssemblies
会将它们加载到当前AppDomain(而不是“ad”变量)
克服此问题的最简单方法是向MarshalByRefObject派生类(示例中的type
变量)添加一个方法,该方法返回AssemblyName
对象,而这些对象不会导致对主AppDomain的泄漏
public AssemblyName[] GetAssemblyNames()
{
return AppDomain.CurrentDomain
.GetAssemblies()
.Select(asm => asm.GetName()).ToArray();
}
而不是:
Assembly[] a = ad.GetAssemblies();
你可以:
AssemblyNames[] a = someRemoteObject.GetAssemblyNames();
其中,someRemoteObject
是调用CreateInstanceAndUnwrap
的返回值