卸载 appdomain 后程序集仍然存在

Posted

技术标签:

【中文标题】卸载 appdomain 后程序集仍然存在【英文标题】:Assembly remains after unloading appdomain 【发布时间】:2021-09-11 17:41:21 【问题描述】:

我有一个程序,它创建AppDomain,在其中加载程序集prelude,然后卸载AppDomain。最后程序列出来自默认 appdomain 的程序集。它是程序的简化版本。在下一个版本中,prelude.dll 将在运行时更改并使用 appdomain 持续执行/卸载。

namespace appdomaintest


    class Program
    
        static void log_assemblies(AppDomain domain)
        
            foreach (var item in domain.GetAssemblies())
            
                Console.WriteLine($"domain.FriendlyName : item.FullName");
            
        
        static void Main(string[] args)
        
            
                var prelude_domain = AppDomain.CreateDomain("PreludeDomain#1", null, null);
                var asm = prelude_domain.Load(new System.Reflection.AssemblyName("prelude"));
                var myint = prelude_domain.CreateInstanceAndUnwrap("prelude", "prelude.MyInt");
                myint.GetType().GetMethod("show").Invoke(myint, new object[0]);
                AppDomain.Unload(prelude_domain);
                Console.WriteLine("AppDomain was unloaded");
            
            log_assemblies(AppDomain.CurrentDomain);
        
    
  

这里是prelude.dll的内容

public class MyInt : MarshalByRefObject

    public MyInt()
    
        Console.WriteLine($"MyInt was constructed in AppDomain.CurrentDomain.FriendlyName");
    
    public void show()
    
        Console.WriteLine($"show in AppDomain.CurrentDomain.FriendlyName");
    

这是程序的输出:

MyInt was constructed in PreludeDomain#1
show in PreludeDomain#1
AppDomain was unloaded
appdomaintest.exe : mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
appdomaintest.exe : appdomaintest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
appdomaintest.exe : prelude, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

不幸的是,我发现我的默认 appdomain 包含 prelude.dll 程序集。据我了解,它一直持续到我的程序执行结束。有什么方法可以防止将其加载到默认的应用程序域?在未来的版本中,prelude.dll 将被重复加载/卸载(其元数据也将被修改)。这就是为什么这种行为不适合我的目的。

在我看来,创建代理对象可能会导致将元数据加载到默认域。但是我怎样才能卸载它们呢?

【问题讨论】:

使用 IPC,我已将它用于从数据库编译运行时剃须刀页面。然后,在单独的进程在 RAM 上变得太大之后 - 杀死它,重新开始。这是目前唯一的方法。 @eocron 这是重型机械。本机进程的创建/中断/互连成本很高。在我的情况下,加载动态程序集的频率非常大。 没有人给你保证。见这里 - docs.microsoft.com/en-us/dotnet/framework/app-domains/… 您要么采用流程方法,要么考虑改变您通过库集成第三方功能的方法(将其切换为服务)。您不需要一直启动本机进程,只需启动它,加载这个东西,卸载它,然后在达到内存或计数限制时关闭进程。 【参考方案1】:

它会保留,是的。没有办法解决它,因为这是不可能的,微软在这里声明:https://docs.microsoft.com/en-us/dotnet/framework/app-domains/how-to-unload-an-application-domain。

使用与另一个进程的进程间通信。您可以启动进程并在其中加载任何内容,直到它变得臃肿,然后您只需将其杀死并重新开始。

您从中获得的一个好处 - 没有人会在您的应用程序意外调用此库中不安全的内容时崩溃。

【讨论】:

您的意思是域中立程序集吗?但是为什么我的程序集是域中立的?

以上是关于卸载 appdomain 后程序集仍然存在的主要内容,如果未能解决你的问题,请参考以下文章

C# 通过 AppDomain 应用程序域实现程序集动态卸载或加载

将 c# 程序集动态加载和卸载到 appdomain

通过应用程序域AppDomain加载和卸载程序集

是否可以避免将一些程序集加载到“AppDomain”中?

C#动态加载dll 时程序集的卸载问题

C# 动态加载/卸载程序集