我们有一个 .NET 2.0 应用程序,它是一个服务,多个客户端主要通过 .NET 远程处理连接。该服务在生产过程中在客户端站点因 OutOfMemory 异常而崩溃,因此目前他们被迫每天左右重新启动一次以避免意外崩溃。
以前,我已经成功解决了托管代码中的几种内存泄漏情况(静态集合未清理其中保存的对象,以及逻辑线程数不断增加的另一种情况)。因此,我非常熟悉捕获内存转储并使用 WinDbg + SOS 搜索它们。
然而,在这种情况下,私有(private)字节不断增加,而所有堆上的字节保持稳定,这表明非托管代码内存泄漏。我收到了包含实际 OOM 异常的故障转储,这使其更加明显:
检查了 Tess Ferandez 的有关处理 .NET 应用程序中非托管代码泄漏的博客以及网络上的其他一些资源,我排除了诸如大量动态程序集之类的问题,这是一种常见的问题XmlSerializer 问题,或第 3 方 native DLL(没有)。然而,周围有大量的P/Invokes。接下来,检查堆返回给我以下内容:
第二个命令也返回所有条目。现在,根据我读到的一些内容,我应该运行 !heap -p -a 来获取堆栈,但我得到的只是
根据this question是不正确的 gflags 使用等。但是,当前不可以在本地启动服务并在其上附加调试器。长话短说,我必须设置一个具有与客户端类似的配置和负载的环境才能完成它,而这还没有准备好。
所以,我陷入了困境。我不知道从这里继续哪里,或者即使我使用正确的方法来解决该问题。非常欢迎任何指点。
编辑 #1: 在使用外部资源的线程上进行 Thread.abort。具体来说,通过 Oracle 的 ODP.NET 提供程序进行数据库连接。这可能是 native 堆泄漏的原因吗?
最佳答案
However, there is a good number of P/Invokes around
Edit #1: Thread.abort on threads that use external resource
遇到这种问题简直就是一场完美的 Storm 。如果它们中的任何一个都足以单独导致不受控制的内存泄漏。在你的开发机器上,一切看起来肯定都很顺利。但它肯定不会执行真实机器正在处理的数据负载类型。
您不会从工具中获得很多帮助,无论如何,不是 .NET 类型的帮助。绝对要从完全摆脱线程中止开始,这永远不会有好结果。您没有提供任何背景信息,因为您很难给出具体建议。一定要使用虚假的自动生成数据建立一个数据库,这样您就可以在舒适的小隔间中检查代码调整的结果。您需要大量数据,因为它泄漏的速度不够快。
如果您仍然遇到问题,那么您需要 gflags.exe 和 umdh.exe 等工具,这些工具可在 Windows 发行版的调试工具中找到。现在是 SDK 的一部分。最后的手段是,它们只能与调试符号配合使用,而 Oracle 并不是那种能够轻松做到这一点的公司。他们的生态系统对于把“我来解决你的问题”的高薪顾问放在一边很友好。如果您找到合适的人,这也可以解决问题。
关于.net - .NET 应用程序中与 native 堆相关的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10553034/