C# 无法卸载程序集,原因不明

C# 无法卸载程序集,原因不明,c#,.net-core,.net-assembly,C#,.net Core,.net Assembly,更新:我已成功将此信息输入WinDbg,并了解了情况。我发现了两件事:第一,这个列表没有被正确发布: private Stack<DependencyAssemblyLoadContext> _loadedContexts; 如果我没看错的话,例外本身就是留在记忆中?由于它来自一个类,该类位于试图卸载的程序集中,因此程序集不会卸载 这似乎。。。古怪的如何摆脱异常引用 问题的原始描述如下,但我已经更新了下面的代码 我有一个POC系统,它扫描一堆DLL,从中加载任务,然后卸载它们。这

更新:我已成功将此信息输入WinDbg,并了解了情况。我发现了两件事:第一,这个列表没有被正确发布:

private Stack<DependencyAssemblyLoadContext> _loadedContexts;
如果我没看错的话,例外本身就是留在记忆中?由于它来自一个类,该类位于试图卸载的程序集中,因此程序集不会卸载

这似乎。。。古怪的如何摆脱异常引用

问题的原始描述如下,但我已经更新了下面的代码


我有一个POC系统,它扫描一堆DLL,从中加载任务,然后卸载它们。这是.NETCore3.0,所以我使用的是
AssemblyLoadContext
。我的加载一切正常,
卸载
事件触发,但当我看到我的模块窗口时,DLL保持加载状态。这与基于
AppDomain
的CLR版本形成对比,在该版本中,DLL在域被拆分时从模块窗口卸载

我想我在某个地方提到了一些东西,但我不知道在哪里,而WinDbg。。。不确定,因为公司对管理权限的限制

主应用程序:

private IFileSystemService _fileSystemService;
private ITaskManagementService _taskManagementService;

static void Main(string[] args)
{
    new Program().Run();
}

public Program()
{
    _fileSystemService = new FileSystemService();
    _taskManagementService = new TaskManagementService();
}

[MethodImpl(MethodImplOptions.NoInlining)]
public void Run()
{
    Console.WriteLine("Getting available files...");
    var files = _fileSystemService.GetFilePaths("*.dll");
    Console.WriteLine($"Found {files.Length} files to scan.");

    Console.WriteLine("Scanning for tasks...");
    var tasks = _taskManagementService.GetAvailableCleanupTasks(files);
    Console.WriteLine($"Total tasks found: { tasks.Count() }");

    while (tasks.Count > 0)
    {
        var task = tasks.Pop();

        Console.WriteLine($"Executing task: { task.GetType().Name }");
        Console.WriteLine("Output:");

        Console.ForegroundColor = ConsoleColor.Green;

        try
        {
            task.Execute<object>();
        }
        catch (Exception ex)
        {
            ex = null;
            continue;
        }
        finally
        {
            Console.ForegroundColor = ConsoleColor.Gray;
            task = null;
        }
    }

    Console.WriteLine("Cleaning up... ");
    _taskManagementService.UnloadAssemblies();
    _taskManagementService = null;
    Console.WriteLine("Cleanup done.");

    GC.WaitForPendingFinalizers();
    GC.Collect();

    Console.WriteLine("Process complete.  Press any key to continue.");
    Console.ReadKey();
}
private Stack<DependencyAssemblyLoadContext> _loadedContexts;

public TaskManagementService()
{
    _loadedContexts = new Stack<DependencyAssemblyLoadContext>();
}

public Stack<ICleanupTask> GetAvailableCleanupTasks(string[] assemblyPaths)
{
    // This application is designed to run every 24 hours, so just unload what we have before reloading
    UnloadAssemblies();

    var results = new Stack<ICleanupTask>();

    // Loads the assembly containing the task loader so it can be used.  The assembly also contains ICleanupTask and CleanupTask.
    foreach (var path in assemblyPaths)
    {
        var context = new DependencyAssemblyLoadContext(path);
        var assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(path));
        var assembly = context.LoadFromAssemblyName(assemblyName);

        foreach (var task in GetTasksFromAssembly(assembly))
        {
            results.Push(task);
        }

        _loadedContexts.Push(context);
    }

    return results;
}

public void UnloadAssemblies()
{
    if (_loadedContexts.Count == 0)
    {
        return;
    }

    while (_loadedContexts.Count > 0)
    {
        var context = _loadedContexts.Pop();
        // context.Unloading += (e) => Console.WriteLine($"Assembly {e.Assemblies.First().GetName()} unloading...");
        context.Unload();
        context = null;
    }
}

private List<ICleanupTask> GetTasksFromAssembly(Assembly assembly)
{
    var tasks = new List<ICleanupTask>();

    foreach (var type in assembly.GetTypes())
    {
        if (type.IsSubclassOf(typeof(CleanupTask)))
        {
            tasks.Add(CreateTask(type));
        }
    }

    return tasks;
}

private ICleanupTask CreateTask(Type taskType)
{
    return (ICleanupTask)Activator.CreateInstance(taskType);
}