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