为什么 IIS 不在池回收时清理旧工作进程 (w3wp.exe) 导致网站内存不足异常?

Why isn't IIS cleaning up the old worker processes (w3wp.exe) on pool recycle leading to website out of memory exception?

我有一个 asp.net-mvc 站点,最近我的 Web 服务器出现内存不足异常。我只有 1 个应用程序池,我们最近将 IIS 设置为在达到一定限制后进行回收。前几天我去了,看到 4 w3wp.exe 个进程 运行(每个都使用了 ~1.8GB 内存)

我假设在回收过程中,它不会杀死旧的工作进程,最终我在我的网站上出现内存不足异常,因为盒子只有 8GB 内存。我可以为盒子添加内存,但我担心为什么这些旧进程没有被清理。

是否有任何建议可以弄清楚为什么这个回收过程没有杀死旧的 w3wp.exe 进程并留下它们 运行?关于理解根本原因甚至解决方法以避免这种风险的任何建议?

应用程序池回收通常会关闭旧的工作进程,所以我认为您没有遇到 IIS 的错误。

请注意,如果进程成为孤立进程,它们的寿命可能会更长,并且根据配置 IIS 必须将它们留在那里供您进行故障排除,

https://www.iis.net/configreference/system.applicationhost/applicationpools/add/failure

如果您不太熟悉调试此类过程,我建议您通过 http://support.microsoft.com 打开一个支持案例,让 Microsoft 支持人员帮助您。

我在 运行 时遇到了类似的问题,例如 FFMpeg.exe 或一些使用 WPF 图形的 PDF 转换,IIS 进程不会关闭并且会发出内存未找到错误。问题不在于 IIS,而是进程中的一些死锁,即使在崩溃后也会阻塞。

解决方法是,将您的网站分成两个独立的网站,一个应该只使用通常不会崩溃的数据库进行事务处理。 video/photo 转换、PDF 转换或任何其他可能导致崩溃的逻辑应移至其他 Web 服务。并在您的网站内部使用 HTTP 调用通过 Web 服务处理它们。

现在,在这种情况下,仍然没有办法解决 web 服务进程崩溃的问题,所以我决定每 100 个请求回收一次应用程序池工作者(我在观察了几个请求后选择了这个数字,平均而言它会仅在达到 200 个请求后才超过 1GB)并且我通过为每个池创建 4 个进程将应用程序池变成 Web Garden。

此设置的优点是,您将来可以轻松地将 Web 服务进程移动到其他机器,每个池可以 increase/decrease 个进程数。而您的主要网站,它只是简单地进行交易流程,变得高度响应,因为它不受 Web 服务流程回收的影响。

您应该关注的主要嫌疑人是实现 IDisposable 的 类 以及不调用 Dispose() 的任何使用。我有一个类似的问题,我已经将其作为对 .

的回复发布了

最可能的原因是您没有在数据库连接上调用 .Dispose()。人们往往对此感到困惑,因为 .NET 的 built-in 连接池使它 听起来像 你不应该处理连接。但是,在请求结束时(或当您使用完连接时)调用 .Dispose() 正是您应该做的以防止资源泄漏。连接池预计会发生这种情况。

我认为 4 w3wp.exe 个进程不是什么大问题 - IIS 产生多个进程是正常的。但很明显,您的应用程序存在需要解决的资源泄漏问题。如上所述,首先查看 IDisposable。如果仍有问题,请查看缓存中的项目并尝试确定是否有更有效的缓存策略可供您使用。如果一切都失败了,分析应用程序以查看您是否可以找到资源泄漏的源头。您的应用程序很可能 应该 在某个地方实现 IDisposable 而不是。

因为您post很清楚,将 IIS 设置为在达到特定限制后回收 正在创建一个新的应用程序池。

older 没有被终止可能有多种原因。

一个可能是内存泄漏,没有处理掉un-managed资源,你可以找这个。

要找出另一个原因,在 IIS 中启用 "Process Orphaning"。 要找出罪魁祸首进程,您可以使用“Process Explorer”。

您还可以选择设置一个可执行文件,这将在进程被孤立/放弃时执行。

即时解决方案也可能是在某个 CPU 限制后将操作设置为 KillW3p。

<applicationPools>
   <add name="DefaultAppPool">
     <cpu limit="80000" action="KillW3wp" resetInterval="00:02:00" />
   </add>
</applicationPools>

在任务管理器中右键单击“旧”w3wp 进程,select“创建转储”,然后在 Visual Studio 中浏览该转储(只需启动一个空 Visual Studio 并将 DMP 文件拖放到它上面)。

那你就一清二楚是怎么回事,不用猜,不用算命

您可以点击“调试托管代码”,看看进程在做什么。是否有任何异步任务在等待或阻塞?是否有任何后台任务可能已通过 HostedService 取消正常关机? “并行堆栈”视图怎么样?启动了多少个线程?加载了哪些模块?

P.S。是的,IIS 在回收后保留旧进程 2-5 分钟是正常的。