如何从主AppDomain卸载程序集?

时间:2008-09-23 19:50:58

标签: c# .net appdomain

我想知道如何卸载加载到主AppDomain中的程序集。

我有以下代码:

var assembly = Assembly.LoadFrom( FilePathHere );

我需要/希望能够在完成后卸载这个程序集。

感谢您的帮助。

8 个答案:

答案 0 :(得分:34)

对于.net版本核心3.0及更高版本:

您现在可以卸载程序集。请注意,.net核心中不再提供appdomains。相反,您可以创建一个或多个AssemblyLoadContext,通过该上下文加载程序集,然后卸载该上下文。请参阅AssemblyLoadContextthis tutorial that simulates loading a plugin then unloading it

.net core 3之前的.net版本,包括netframework 4及更低版本

您无法从应用程序域卸载程序集。您可以销毁appdomains,但是一旦将程序集加载到appdomain中,它就会存在于appdomain的生命周期中。

见Jason Zander对Why isn't there an Assembly.Unload method?

的解释

如果您使用的是3.5,则可以使用AddIn Framework来更轻松地管理/调用不同的AppDomain(您可以卸载,卸载所有程序集)。如果您之前使用的是版本,则需要自己创建一个新的appdomain来卸载它。

答案 1 :(得分:21)

我也知道这已经很老了,但可能会帮助有这个问题的人! 这是我发现的一种方法! 而不是使用:

var assembly = Assembly.LoadFrom( FilePathHere );

使用它:

var assembly = Assembly.Load( File.ReadAllBytes(FilePathHere));

这实际上加载了"内容"汇编文件,而不是文件本身。这意味着程序集文件上没有文件锁!所以现在可以复制,删除或升级它而无需关闭应用程序或尝试使用单独的AppDomain或Marshaling!

PROS:使用1个代码修复非常简单! 缺点:无法使用AppDomain,Assembly.Location或Assembly.CodeBase。

现在您只需要销毁在程序集上创建的任何实例。 例如:

assembly = null;

答案 2 :(得分:15)

如果不卸载整个AppDomain,则无法卸载程序集。 Here's why

  
      
  1. 您正在应用域中运行该代码。这意味着可能存在呼叫站点和调用堆栈,其中包含期望继续工作的地址。

  2.   
  3. 假设您确实设法跟踪程序集的所有句柄和对已运行代码的引用。假设您没有使用代码,一旦成功释放了程序集,您就只释放了元数据和IL。 JIT代码仍然在app域加载器堆中分配(JIT'd方法按照调用它们的顺序在缓冲区中按顺序分配)。

  4.   
  5. 最后一个问题涉及已加载共享的代码,否则更正式地称为“域中立”(在ngen工具上签出/共享)。在此模式下,生成程序集的代码将从任何应用程序域执行(没有硬连线)。

  6.         

    建议您自然地围绕应用程序域边界设计应用程序,完全支持卸载。

答案 3 :(得分:9)

您应该在另一个AppDomain中加载临时程序集,在不使用时,您可以卸载AppDomain。它安全而快速。

答案 4 :(得分:4)

如果您想拥有可以在以后卸载的临时代码,根据您的需要,DynamicMethod类可能会执行您想要的操作。但是,这并没有给你上课。

答案 5 :(得分:1)

这是一个很好的示例,如何在运行时编译和运行dll,然后卸载所有资源: http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm

答案 6 :(得分:1)

我知道它的旧但可能会帮助某人。您可以从流中加载文件并将其释放。它对我有用。我找到了解决方案HERE

希望它有所帮助。

答案 7 :(得分:0)

作为替代方案,如果程序集刚刚加载,要检查程序集的信息,如publicKey,更好的方法是不加载它,而是首先加载AssemblyName来检查信息。 :

AssemblyName an = AssemblyName.GetAssemblyName ("myfile.exe");
byte[] publicKey = an.GetPublicKey();
CultureInfo culture = an.CultureInfo;
Version version = an.Version;

修改

如果您需要反映程序集中的类型而不将程序集放入应用程序域,则可以使用Assembly.ReflectionOnlyLoadFrom方法。 这将允许您查看它们在程序集中的类型,但不允许您实例化它们,也不会将程序集加载到AppDomain中。

将此示例视为exlanation

public void AssemblyLoadTest(string assemblyToLoad)
{
    var initialAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    Assembly.ReflectionOnlyLoad(assemblyToLoad);
    var reflectionOnlyAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    //Shows that assembly is NOT loaded in to AppDomain with Assembly.ReflectionOnlyLoad
    Assert.AreEqual(initialAppDomainAssemblyCount, reflectionOnlyAppDomainAssemblyCount); // 4 == 4

    Assembly.Load(assemblyToLoad);
    var loadAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //5

    //Shows that assembly is loaded in to AppDomain with Assembly.Load
    Assert.AreNotEqual(initialAppDomainAssemblyCount, loadAppDomainAssemblyCount); // 4 != 5
}