- 原因分析
在 .Net 程序运行时,每个应用程序域(AppDomain)都有其自身的根程序集(Root Assembly)和资源。应用程序域有自己的加载器来加载需要的程序集和资源。当使用 System.AppDomain.Unload()
方法或 AppDomain.CurrentDomain.DomainUnload
事件来卸载域时,可能会抛出 CannotUnloadAppDomainException
异常。这是因为应用程序域中可能存在一些资源或程序集无法被释放导致。
- 解决办法
为了解决这个问题,我们需要找到程序域中不能被卸载的资源,同时对它们进行释放。
2.1 示例一:释放资源
首先,我们需要进行一些排查工作,查找可能导致 CannotUnloadAppDomainException
异常的原因。可以尝试使用以下方式排查问题:
AppDomain.CurrentDomain.DomainUnload += (sender, e) =>
{
Console.WriteLine("Domain Unload started");
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
Console.WriteLine($"Trying to unload {assembly.FullName}");
if (assembly.IsDynamic) continue;
AppDomain.CurrentDomain.ReflectionOnlyLoad(assembly.FullName);
}
catch (Exception ex)
{
Console.WriteLine($"Cannot unload assembly {assembly.FullName}, exception: {ex}");
}
}
};
以上代码可以输出当前程序域中的所有程序集,并在卸载过程中进行释放。如果在释放中出现异常,则会输出异常信息。
2.2 示例二:动态加载程序集
其次,我们可以将一些需要动态加载的程序集放在应用程序域之外,以方便卸载时的释放。可以使用 Assembly.LoadFrom()
方法来动态加载需要的程序集。
private static void LoadAssembly(string path)
{
var assembly = Assembly.LoadFrom(path);
Console.WriteLine($"Loaded assembly {assembly.FullName} from {path}");
}
以上代码会将需要动态加载的程序集放在应用程序域之外,卸载时可以更轻松地释放。