我们的混合经典 ASP/.NET 网站已经存在内存不足问题很长一段时间了。基本上,我们看到了几种不同的情况:
- 某些请求(返回大型记录集的 SQL 查询)导致内存急剧增加(私有字节和虚拟字节),并且 IIS 工作进程崩溃,并且应用程序池回收。
- 专用字节保持“正常”,但虚拟字节达到最大值(~2GB),并且 IIS 工作进程崩溃,应用程序池回收。
崩溃的 EventID 为:1009、1011 和 1013。
在这两种情况下,ASP 都会在我们的应用程序日志中报告内存不足消息。
如果我们确实“内存不足”,为什么应用程序中已有的用户仍然可以工作,而新用户甚至无法登录?这是否意味着无法满足任何请求?
显然,IIS 仍然可以提供服务一些请求——所以答案可能是这取决于具体请求。也许其中一个比另一个更“昂贵”?
无论如何,我最终的问题是——应用程序池在什么时候会说足够了,我必须回收?
我们运行了 DebugDiag,发现一些堆的碎片率超过 90% 甚至 100%,因此仅当碎片率高且没有更多堆空间时才会进行回收?
这是一个稍微主观的问题,但我希望我能得到一些关于这个阈值的意见!
谢谢。
答案1
除非工作进程破坏了您配置的回收标准之一(虚拟字节限制似乎是一个好的标准?)或无法响应 ping,否则它不会被回收。
应用程序(ISAPI)可以将自身报告为不健康,从而触发回收,但这种情况发生在相当狭窄的条件下。
你的应用程序在运行时基本上会分散内存,并且 OOM 反映了这一点 - 没有空闲连续的,未分配的内存可用于新的分配;它们会失败。
根据描述,您可以选择以下选项:
修复分配模式
将应用程序的各个部分分离到单独的应用程序池中(例如,将 .Net 与 ASP 分开运行) - 并非所有应用程序都可以以这种方式拆分,但对于可以拆分的应用程序来说,这很容易。两个应用程序池 = 2 个(或更多)工作进程 = 每个工作进程 2GB 地址空间
实施虚拟字节限制,以便在应用程序池变得太大时回收它
实施每日回收,以防止应用程序达到整个内存空间碎片化的程度
如果你的应用是无状态的,请尝试网络园艺;增加最大工作进程数,以更长时间地避免故障
在 64 位系统上作为 32 位应用程序运行;为工作进程提供 4GB。
本质上,如果(无论什么)堆变得非常碎片化,那么您就会陷入死亡螺旋,并且需要一个新的工作进程。
IIS 没有内置安全带,因此在到达该点之前对您的进程实施回收限制 - 或者只是说“忘掉它,我要使用 64 位!”可能是可行的解决方案。