我有一个 .NET 3.5 SP1 应用程序,它是一个 Excel 插件。该应用程序分为父AppDomain
域(Excel)和子域,我们在其中加载所有 dll。当我们希望更新我们的应用程序时,我们会卸载子域,替换文件并重新加载它。
不幸的是,卸载域将激活 2 个工作线程,它们将开始消耗 CPU 周期 (20-40%)。
如果我使用 VS 2010 进行调试,则在 之前和之后的时刻,AppDomain.Unload
除了 Excel 的主线程之外,没有任何线程在调用堆栈中处于活动状态。AppDomain.Unload
确实已卸载,因为如果我再次尝试调用 Unload,我会得到一个AppDomainUnloadedException
.
如果我使用 ProcessExplorer,我可以看到 2 个线程正忙于工作,即使 VS 调试器已经中断。查看调用堆栈什么也没有显示,因为没有符号。
- ntkrnlpa.exe+0x6eacb
- ntkrnlpa.exe+0x2bfd0
- hal.dll+0x2ef2
- ntkrnlpa.exe+0x6a6cf
- ntdll.dll+0xe514
- mscorwks.dll+0x992d
- mscorwks.dll+0x52568
- mscorwks.dll+0x15b469
- kernel32.dll+0xb729
如果我使用 WinDbg,我可以看到 2 个叛徒线程的调用堆栈。它总是一样的:
- 警告:堆栈展开信息不可用。以下框架可能是错误的。
- ntdll!KiFastSystemCallRet
- mscorwks+0x992d
- mscorwks!InstallCustomModule+0x1eca0
- mscorwks!CorExitProcess+0x503b
- kernel32!GetModuleFileNameA+0x1ba
我创建了一个非常简单的测试应用程序来加载/卸载子程序集。使用简单的 1 类程序集执行此操作时,它可以正常工作。如果我让它加载/卸载真实应用程序的子域,它会触发相同的叛徒线程。
创建子域的代码如下:
AppDomainSetup appSetup = new AppDomainSetup();
appSetup.ApplicationBase = baseDir;
var ps = new PermissionSet(System.Security.Permissions.PermissionState.Unrestricted);
return AppDomain.CreateDomain(name, null, appSetup, ps, null);
从父域到子域的通信是通过代理和反射。创建它的代码如下:
string assName = typeof(ApplicationProxy).Assembly.FullName;
string className = typeof(ApplicationProxy).FullName;
var obj = _childDomain.CreateInstanceAndUnwrap(assName, className, false,
System.Reflection.BindingFlags.Default,
null, new object[]{_sessionGuid},
CultureInfo.InvariantCulture,
null, new Evidence(AppDomain.CurrentDomain.Evidence));
_proxy = (ApplicationProxy)obj;
我用谷歌搜索了很多问题,找不到任何有类似问题的人。该应用程序有 10 个项目大,所以我不能发布它。
我想知道是否有人遇到过类似的事情并有一些提示给我。否则有人对如何解决这个问题有任何想法吗?