我对Unload
中的方法AssemblyLoadContext
感到奇怪。原始代码来自https://github.com/dotnet/coreclr/pull/22221/files/a7cbc5c8d1bd48cafec48ac50900ff9e96c1485c#diff-cf594171be5712641ea4416aadc2f83f,我使用的是dotnet core 3.0.100-preview3-010431
在这种情况下效果很好:
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
namespace example
{
class TestAssemblyLoadContext : AssemblyLoadContext
{
public TestAssemblyLoadContext() : base(true)
{
}
protected override Assembly Load(AssemblyName name)
{
return null;
}
}
class Manager
{
[MethodImpl(MethodImplOptions.NoInlining)]
public void Execute(out WeakReference testAlcWeakRef)
{
var alc = new TestAssemblyLoadContext();
testAlcWeakRef = new WeakReference(alc);
alc.Resolving += (alc2, assemblyName) =>
{
var dllName = assemblyName.Name.Split(',').First();
return alc2.LoadFromAssemblyPath(@"absolute\path\lib.dll");
};
Assembly a = alc.LoadFromAssemblyPath(@"absolute\path\lib.dll");
var args = new object[] { 3, 2 };
var methodInfo = a.GetExportedTypes()[0].GetMethods().Where(m => m.Name == "MethodName").ToList()[0];
var result = methodInfo.Invoke(Activator.CreateInstance(a.GetExportedTypes()[0]), args);
alc.Unload();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void Unload(WeakReference testAlcWeakRef)
{
for (int i = 0; testAlcWeakRef.IsAlive && (i < 10); i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine($"is alive: {testAlcWeakRef.IsAlive}");
}
}
class Program
{
static void Main(string[] args)
{
var manager = new Manager();
manager.Execute(out var testAlcWeakRef);
manager.Unload(testAlcWeakRef);
}
}
}
但是我以后需要调用Unload
方法。因此,我将alc.Unload()
移到了manager.Unload()
中,而alc.Unload()
无法正常工作。我在做什么错了?
不起作用的情况:
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
namespace example
{
class TestAssemblyLoadContext : AssemblyLoadContext
{
public TestAssemblyLoadContext() : base(true)
{
}
protected override Assembly Load(AssemblyName name)
{
return null;
}
}
class Manager
{
[MethodImpl(MethodImplOptions.NoInlining)]
public void Execute(out WeakReference testAlcWeakRef, out TestAssemblyLoadContext alc)
{
alc = new TestAssemblyLoadContext();
testAlcWeakRef = new WeakReference(alc);
alc.Resolving += (alc2, assemblyName) =>
{
var dllName = assemblyName.Name.Split(',').First();
return alc2.LoadFromAssemblyPath(@"absolute\path\lib.dll");
};
Assembly a = alc.LoadFromAssemblyPath(@"absolute\path\lib.dll");
var args = new object[] { 3, 2 };
var methodInfo = a.GetExportedTypes()[0].GetMethods().Where(m => m.Name == "MethodName").ToList()[0];
var result = methodInfo.Invoke(Activator.CreateInstance(a.GetExportedTypes()[0]), args);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void Unload(WeakReference testAlcWeakRef, TestAssemblyLoadContext alc)
{
alc.Unload();
for (int i = 0; testAlcWeakRef.IsAlive && (i < 10); i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine($"is alive: {testAlcWeakRef.IsAlive}");
}
}
class Program
{
static void Main(string[] args)
{
var manager = new Manager();
manager.Execute(out var testAlcWeakRef, out var alc);
manager.Unload(testAlcWeakRef, alc);
}
}
}
答案 0 :(得分:0)
备注:
- 只有可收集的AssemblyLoadContext才能卸载。
- 卸载将异步进行。
- 在引用AssemblyLoadContext时不会发生卸载。
您的 alc 变量阻止了上下文的卸载。
可能的解决方案:
[MethodImpl(MethodImplOptions.NoInlining)]
public void Unload(WeakReference testAlcWeakRef, ref TestAssemblyLoadContext alc)
{
alc.Unload();
alc = null;
for (int i = 0; testAlcWeakRef.IsAlive && (i < 10); i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine($"is alive: {testAlcWeakRef.IsAlive}");
}