我有有效的代码(所有这些try
-catch
看起来都很疯狂,但我真的需要它们来说明问题):
Exception doStuffException = null;
try {
someComObject.DoStuff();
} catch( Exception e ) {
doStuffException = e;
throw;
} finally {
try {
someComObject.Cleanup();
} catch( Exception e ) {
var processes = Process.GetProcesses();
foreach( var p in processes ) {
//log p.Threads.Count and p.ProcessName
}
throw;
}
}
COM对象驻留在进程外服务器进程中。客户端和COM服务器都在Azure web角色中运行,我不知道在Azure之外是否会再次发生同样的行为。
大多数时候,它只是起作用——DoStuff()
运行正常,然后Cleanup()
运行正常。有时在一些特定的数据集上,DoStuff()
产生System.OutOfMemoryException
,然后Cleanup()
运行并产生System.Runtime.InteropServices.COMException
,错误代码0x800700A4
对应于winerror.h中定义的ERROR_MAX_THRDS_REACHED
,并具有文本"系统中无法再创建线程"。枚举所有进程的代码运行,没有任何进程有任何不合理的线程数,托管COM服务器的进程的线程数等于3(是的,只有三个)。
一旦ERROR_MAX_THRDS_REACHED
发生,对该COM服务器的所有调用也会产生ERROR_MAX_THRDS_REACHED
,直到COM服务器重新启动。
当线程没有明显泄漏时,是什么原因导致ERROR_MAX_THRDS_REACHED
?
经过多次观察,很明显,在大多数情况下,问题都会重现,COM服务器进程几乎会消耗所有内存(COM服务器是一个32位进程,因此它消耗的内存不能超过2GB)。
这种情况可能是由于内存碎片或内存泄漏造成的——如果不进行进一步分析,很难说。这反过来可能导致没有足够的内存来创建新线程(为COM客户端请求提供服务所需),后者可能被诊断为"无法创建更多线程",而不是COM服务器中的"内存不足"(错误代码返回给客户端并由客户端观察)。
我没有证据表明它正是这样起作用的,但这是我能想到的最好的解释。看起来只是内存不足导致无法创建新线程,并被报告为"无法创建更多线程"。