使用AppDomain加载/卸载外部程序集

Bol*_*ski 13 .net c#

我的方案如下:

  • 创建新的AppDomain
  • 将一些组件加载到其中
  • 加载dll做一些魔法
  • 卸载AppDomain以释放内存和已加载的库

下面是我正在尝试使用的代码

    class Program
{
    static void Main(string[] args)
    {
        Evidence e = new Evidence(AppDomain.CurrentDomain.Evidence);
        AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
        Console.WriteLine("Creating new AppDomain");
        AppDomain newDomain = AppDomain.CreateDomain("newDomain", e, setup);
        string fullName = Assembly.GetExecutingAssembly().FullName;
        Type loaderType = typeof(AssemblyLoader);
        var loader = (AssemblyLoader)newDomain.CreateInstanceFrom(loaderType.Assembly.Location, loaderType.FullName).Unwrap();
        Console.WriteLine("Loading assembly");
        Assembly asm = loader.LoadAssembly("library.dll");
        Console.WriteLine("Creating instance of Class1");
        object instance = Activator.CreateInstance(asm.GetTypes()[0]);
        Console.WriteLine("Created object is of type {0}", instance.GetType());
        Console.ReadLine();
        Console.WriteLine("Unloading AppDomain");
        instance = null;
        AppDomain.Unload(newDomain);
        Console.WriteLine("New Domain unloaded");
        Console.ReadLine();
    }

    public class AssemblyLoader : MarshalByRefObject
    {
        public Assembly LoadAssembly(string path)
        {
            return Assembly.LoadFile(path);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

library.dll只包含一个虚拟类,带有一个巨大的字符串表(更容易跟踪内存消耗)

现在的问题是内存实际上没有被释放.更令人惊讶的是,在AppDomain.Unload()之后,内存使用量实际上增加了

任何人都可以对这个问题有所了解吗?

Bri*_*sen 7

这不是一个完整的答案:我只是注意到你使用一个字符串作为有效载荷.字符串对此没有用,因为字符串是实例化的.Interned字符串在AppDomains之间共享,因此卸载AppDomain时不会卸载该部分.尝试使用byte []代替.


Bol*_*ski 6

回答我自己的问题 - 不知道是否有更好的方法在StackOverflow上做...如果有,我会感激指示......无论如何,通过互联网挖掘我找到了另一个解决方案,我希望更好.以下代码,如果有人发现任何弱点 - 请回复.

class Program
{
    static void Main(string[] args)
    {
        Console.ReadLine();
        for(int i=0;i<10;i++)
        {
            AppDomain appDomain = AppDomain.CreateDomain("MyTemp");
            appDomain.DoCallBack(loadAssembly);
            appDomain.DomainUnload += appDomain_DomainUnload;

            AppDomain.Unload(appDomain);        
        }

        AppDomain appDomain2 = AppDomain.CreateDomain("MyTemp2");
        appDomain2.DoCallBack(loadAssembly);
        appDomain2.DomainUnload += appDomain_DomainUnload;

        AppDomain.Unload(appDomain2);

        GC.Collect();
        GC.WaitForPendingFinalizers();  
        Console.ReadLine();
    }

    private static void loadAssembly()
    {
        string fullPath = @"E:\tmp\sandbox\AppDomains\AppDomains1\AppDomains1\bin\Debug\BigLib.dll";
        var assembly = Assembly.LoadFrom(fullPath);
        var instance = Activator.CreateInstance(assembly.GetTypes()[0]);
        Console.WriteLine("Creating instance of {0}", instance.GetType());
        Thread.Sleep(2000);
        instance = null;
    }

    private static void appDomain_DomainUnload(object sender, EventArgs e)
    {
        AppDomain ap = sender as AppDomain;
        Console.WriteLine("Unloading {0} AppDomain", ap.FriendlyName);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

我已经发布了一个示例,其中3个不同的程序集在不同的应用程序域中加载并成功卸载.这是链接http://www.softwareinteractions.com/blog/2010/2/7/loading-and-unloading-net-assemblies.html


Vit*_*sky 1

每个程序集也被加载到主域中。由于您使用程序集实例,因此您的主域会加载此程序集以便能够分析其中的所有类型。

如果您想阻止在两个域中加载程序集 - 使用 AppDomain.CreateInstance 方法。