托管在Azure应用程序服务中的.Net Web API-随着时间的推移内存消耗和性能下降

托管在Azure应用程序服务中的.Net Web API-随着时间的推移内存消耗和性能下降,.net,azure,memory-leaks,azure-web-app-service,webapi,.net,Azure,Memory Leaks,Azure Web App Service,Webapi,所讨论的环境是一个多租户环境。由同一资源组中的2个app服务计划组成;其中一个包含.NET Framework Web API,另一个包含面向前端的客户端(这是一个ASP.NET Web表单应用程序)。这两个计划都在P1V3订阅上运行(195分钟ACU/VCPU,8GB内存,2VCPU)。我们将它们分为不同计划的原因是为了能够应用更多定制的扩展设置(但扩展设置不是我发布此问题的原因) 最近,我们一直在进行一些性能改进。我们已经查明了某些依赖性是如何造成大量等待时间和系统不稳定的。然后重新设计/重

所讨论的环境是一个多租户环境。由同一资源组中的2个app服务计划组成;其中一个包含.NET Framework Web API,另一个包含面向前端的客户端(这是一个ASP.NET Web表单应用程序)。这两个计划都在P1V3订阅上运行(195分钟ACU/VCPU,8GB内存,2VCPU)。我们将它们分为不同计划的原因是为了能够应用更多定制的扩展设置(但扩展设置不是我发布此问题的原因)

最近,我们一直在进行一些性能改进。我们已经查明了某些依赖性是如何造成大量等待时间和系统不稳定的。然后重新设计/重新构建许多方面以缓解这些限制。我们认为我们已经有了相当不错的进步。然而,我们仍在经历应用程序服务计划(WebAPI)中内存的逐渐增加,而且永远不会恢复

我相信,随着时间的推移,这将导致服务质量的下降。例如,加载登录页(需要加载一些用户设置)而无需大量使用大约需要2秒钟;但是,当系统已经使用了相当长的时间(并且会消耗相当多的内存)时,最终需要6-10秒

我尝试从应用程序洞察/实时指标监控“提交内存”

启动后,我看到“提交内存”指标稳定在258mb。然后我开始连续发送大约40分钟的请求(向API发送270个请求),内存增加到529mb

我停止了请求并继续监视;记忆一点一点地继续增长;没有任何实际用途。将发送的唯一请求是Azure 5分钟刷新(因为应用程序设置为不空闲)

我试过的

  • 我开始处理为普通请求初始化的大型对象,并在API控制器级别的Dispose Overrides方法中触发GC.Collect()

  • 目前我主要关注3个特定的请求(上面的测试中使用的请求),并实现了Try/Catch/Finally块中主要对象/数据表的清除

我的问题是:

  • Application Insights/Live Metrics部分中的“提交内存”是否为“当前正在使用”内存?如果是,这是否构成内存泄漏?(从我有意关注的请求来看,我认为内存泄漏的可能性很小,因为它们非常简单,我们没有使用非托管代码或其他代码)

  • 这种行为的原因可能是什么?这在Azure应用程序服务环境中是否正常

  • 也许是应用程序被迫不空闲的事实限制了垃圾收集的发生?为什么GC.Collect()在显式调用时不清理内存呢

  • 在我们的例子中,这可能与计划有关吗

  • 应用程序洞察是否有助于增加内存消耗?或者更糟糕的是,限制它释放内存

  • 在清理我们可能过度寻找的内存/资源方面,还有其他事情要做吗

  • 在使用数小时/数天(无需重新启动)且未正确释放内存/资源后,性能极有可能下降,这一假设是否正确?还有什么会导致性能下降

  • 更新-

    再过一两个小时,我访问了特定于应用程序的指标,并将其与应用程序洞察进行了比较(请注意,应用程序服务计划仅包含Web API!)


    为什么会有差异?哪一个是对的

    让我看看能不能解释一下你的问题。首先,.NET设计用于在需要时清除内存。还有一些其他参数,但发现如果GC不经常尝试收集,“服务器”(原始设计)更有效。将1和0存储在不使用的内存中的区别并不像每次都清除一样阴险(阅读Richter在.NET上的书来了解一些内部内容——云仍然有相当一部分适用)

    至于正常情况,有些可能是这样,但你比我通常看到的要大得多。你的时间从2秒(在我看来太长了)增加到6秒,这表明你有问题。很可能代码中有什么东西。我以前见过这个吗?是的,在一个架构糟糕的应用程序中——从好的方面来说,情况要糟糕得多,而且会从飞行状态变为完全静止状态,需要手动干预。这里的原因可能与您的不同,是决定将云服务端(不是真正的API)上的数据访问作为中心中心,获取对象和命令类型,然后解析以发送正确的命令(也就是说,为了让应用程序构建从POCOs自动生成,应用程序构建器的设计师重新设计了LINQ到SQL的工作原理)。是的,这是一个离题,但数据库阻塞可以很容易地级联到web API,因此这是一个检查(数据访问或数据库代码)的好地方

    应用程序没有空闲?可能,但更可能的情况是,内存中还有其他存储位,比如数据库上的死锁或竞争条件,或者web API中的一些架构问题

    至于GC,即使显式调用它也不是一个灵丹妙药。事实上,它比允许框架引擎中的比特为您处理GC更糟糕。注意:许多网站建议您不要显式调用collect(是的,如果被认为存在问题,GC.collect()也不能保证强制立即收集)简言之,缺乏GC不太可能成为问题

    这些计划对绩效有一定影响,但是