如何从主AppDomain卸载程序集?


38

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

我有以下代码:

var assembly = Assembly.LoadFrom(FilePathHere); 

我需要/想能当我完成卸载该组件。

感谢您的帮助。

+1

尽量不要使用LoadFrom,它在与Load上下文不同的上下文中并可能导致问题。 24 9月. 082008-09-24 01:09:32

  0

好问题,但我看不到任何关于如何解决的清晰答案var assembly = Assembly.LoadFrom(FilePathHere); 13 7月. 122012-07-13 17:09:35

32

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

Why isn't there an Assembly.Unload method?

见杰森Zander的解释如果您使用的3.5,您可以使用外接程序框架,使其更易于管理/调用到不同的应用程序域(你可以卸载,卸载所有的组件) 。如果您之前使用的是版本,则需要自己创建一个新的AppDomain以卸载它。

  0

我以为这改变了.NET 3.5? 23 9月. 082008-09-23 19:52:46

+1

有没有计划允许从应用程序域卸载程序集(我不希望他们要么,这是很难做的,那些关心将使用更安全和更清洁的解决方法)。你可以做的最好的是Khoth提到的轻量级代码生成 20 3月. 092009-03-20 14:46:17


14

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

  1. 您正在运行的应用程序域代码。这意味着有潜在的呼叫站点和呼叫堆栈,其中有地址,期望继续工作。

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

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

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


4

如果您想要临时代码可以随后卸载,根据您的需要,DynamicMethod类可能会做你想做的。尽管如此,这并不能为你提供课程。


8

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

+2

请参阅AppDomain.DoCallback,同时参见MarshalByRefObject:你创建了一个MarshalByRefObject“invoker”,它有一个你想做的事情并且在其可变字段中返回一些东西,你创建一个临时的AppDomain并调用dom.DoCallback(invoker.DoSomething)使这个对象做你想要的;那么你从appdomain中的调用者收集结果并卸载临时域。 19 7月. 112011-07-19 15:23:27

  0

@jkff:不幸的是,如果使用MarshalByRefObject,就像在PingPong例子中一样,Assembly.LoadFrom将像在主AppDomain中一样执行,所以卸载临时AppDomain仍然会产生无法卸载程序集的旧问题。我想你可能需要以某种方式序列化你想从临时AppDomain获得的数据,而不用封送,如果你想访问它并仍然可以卸载程序集。 08 5月. 132013-05-08 16:30:37

  0

@jkff:虽然你可能是对的......但它并不像MSDN示例中所描述的那么简单。一个可能应该使用tempAppDomain.CreateInstanceAndUnwrap ...并且甚至可能需要使用AppDomain.GetData和SetData。 (如果仅用于加载和卸载应用程序,这并不会真正使应用程序域变得混乱。) 08 5月. 132013-05-08 19:57:42


1

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


0

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

希望它有帮助。


13

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

var assembly = Assembly.LoadFrom(FilePathHere); 

使用本:

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

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

优惠价:非常容易修复1代码! CONS:无法使用AppDomain,Assembly.Location或Assembly.CodeBase。

现在你只需要销毁在程序集上创建的所有实例。 例如:

assembly = null; 
  0

“**不能使用AppDomain **”表示您不能在该程序集内启动一个,或者您可以更具体?那么'AppDomain.CurrentDomain.Load(File.ReadAllBytes(FilePathHere));'在这个特定的场景中与Assembly.Load有什么不同吗? 23 10月. 162016-10-23 03:29:43


0

作为替代,如果组件只是装载在第一位置,以检查如公钥组件的信息,更好的方法是将不加载它,而检查信息通过首先加载AssemblyName:

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