这是一个 netcore 问题,而不是 NETFX 问题。
此检查演示了该行为。您将需要提供一个程序集以使其加载并使代码中的名称与文件系统中的名称匹配。
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading;
namespace unload
{
public class ALC : AssemblyLoadContext
{
public ALC() : base(isCollectible: true) { }
protected override Assembly Load(AssemblyName name) => null;
}
class Program
{
static void Main(string[] args)
{
var alc1 = new ALC();
var alc2 = new ALC();
Assembly assy1, assy2;
using (var stream = new FileStream("./assy.dll", FileMode.Open))
assy1 = alc1.LoadFromStream(stream);
using (var stream = new FileStream("./assy.dll", FileMode.Open))
assy2 = alc2.LoadFromStream(stream);
var currentDomain = AppDomain.CurrentDomain;
alc1.Unloading += alc =>
{
Console.WriteLine("alc1 HAS UNLOADED");
};
alc2.Unloading += alc =>
{
Console.WriteLine("alc2 HAS UNLOADED");
};
alc1.Unload();
assy1 = null;
alc1 = null;
alc2.Unload();
assy2 = null;
alc2 = null;
GC.Collect(); //no refs and force GC
Thread.Sleep(100); // let other things complete
var duplicates = from a in currentDomain.GetAssemblies() group a by a.FullName into g where g.Count() > 1 select g;
while (duplicates.Any())
{
GC.Collect();
Thread.Sleep(500);
duplicates = from a in currentDomain.GetAssemblies() group a by a.FullName into g where g.Count() > 1 select g;
Console.WriteLine(string.Join(", ", duplicates.Select(g => $"{g.Count()} {g.Key}")));
}
}
}
}
如果您运行此程序,您将看到卸载事件触发,但程序集的两个实例继续由currentDomain.GetAssemblies()
.
文档AssemblyLoadContext.Unload()
说
- 一个 AssemblyLoadContext 只能在它是可收集的情况下被卸载。
- 卸载将异步进行。
- 存在对 AssemblyLoadContext 的引用时不会发生卸载
我相信这个例子满足了所有这些要求。还有什么可能干扰?有任何已知的错误吗?
是否有可能实际卸载了程序集但 currentDomain 未能更新其簿记?你会怎么说?