首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >与常规垃圾收集相比,AssemblyLoadContext.Unload()在.NET内核中的价值是什么?

与常规垃圾收集相比,AssemblyLoadContext.Unload()在.NET内核中的价值是什么?
EN

Stack Overflow用户
提问于 2020-02-17 11:30:47
回答 1查看 2.2K关注 0票数 1

.NET Core3.0引入了可收集的AssemblyLoadContext,它允许调用Unload()方法卸载上下文中加载的程序集。

根据文档(https://learn.microsoft.com/en-us/dotnet/standard/assembly/unloadability#troubleshoot-unloadability-issues),卸载是异步的,任何对上下文或对象的引用都会阻止上下文卸载。

我想知道如果我失去了对AssemblyLoadContext的引用,这会不会导致泄漏(因为我没有更多的上下文来调用Unload() )。测试证明,这不会导致泄漏,即使没有显式调用Unload(),也将卸载未使用的程序集:

代码语言:javascript
运行
复制
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using NUnit.Framework;

namespace Tests.Core
{
    [TestFixture]
    public class CollectibleAssemblyLoadContextTests
    {
        private const string AssemblyName = "Test___DynamicAssembly";

        [Test]
        [TestCase(/*unload*/ true,  /*GC sessions*/ 1)]
        [TestCase(/*unload*/ false, /*GC sessions*/ 2)]
        public void ShouldExecuteAndUnload(bool unload, int expectedGcSessions)
        {
            string actual = Execute(10, unload);
            Assert.AreEqual("executed 10", actual);

            int gcSessions = 0;
            while (!IsUnloaded())
            {
                GC.Collect();
                gcSessions++;
            }

            Assert.AreEqual(expectedGcSessions, gcSessions);
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        private bool IsUnloaded()
        {
            return !AppDomain.CurrentDomain.GetAssemblies()
                .Select(x => x.GetName().Name)
                .Contains(AssemblyName);
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        private string Execute(int number, bool unload)
        {
            var source = @"
        public static class Process
        {
            public static string Execute(int i)
            {
                return $""executed {i}"";
            }
        }";
            var compilation = CSharpCompilation.Create(AssemblyName, new[] {CSharpSyntaxTree.ParseText(source)},
                new []{MetadataReference.CreateFromFile(typeof(object).Assembly.Location)},
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            using var ms = new MemoryStream();
            compilation.Emit(ms);
            ms.Seek(0, SeekOrigin.Begin);

            var assemblyLoadContext = new AssemblyLoadContext("CollectibleContext", isCollectible: true);

            Assembly assembly = assemblyLoadContext.LoadFromStream(ms);
            if (unload)
                assemblyLoadContext.Unload();

            Type type = assembly.GetType("Process");
            MethodInfo method = type.GetMethod("Execute");
            return (string)method.Invoke(null, new object[] {number});
        }
    }
}

这个测试还显示,使用Unload()在一个GC会话之后卸载上下文,不管没有Unload(),卸载都需要两个会话。但可能只是巧合,而且不总是可以复制的。

所以,考虑到

  1. 对可收集上下文的任何引用都将阻止它卸载(因此,在加载所有需要计划卸载的程序集之后,当它不使用时调用Unload()是可能的)。

这个Unload()方法的目的是什么?使用Unload()和仅仅依赖GC有什么区别?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-25 22:50:56

我有同样的印象,我做的测试也是一样的。似乎显式调用Unload()是没有意义的。然后我找到了https://github.com/dotnet/samples/blob/master/core/tutorials/Unloading,并意识到如果您在那里注释Unload(),库将不会被卸载。这是行https://github.com/dotnet/samples/blob/master/core/tutorials/Unloading/Host/Program.cs#L74。最终,就像LasseV.Karlsen说的那样。如果显式调用Unload(),则可以预期您的库将更快地卸载。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60261523

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档