.NET Core high memory usage in Docker (AWS ECS Fargate)(Docker中的.NET核心高内存使用率(AWS ECS Fargate))
问题描述
以下是对该应用程序的描述。我有一个运行Hangfire的控制台应用程序。有几个工作是重复进行的。尤其是一个作业,它要解析几个大型的XML文件。我将此控制台应用程序部署为AWS ECS Fargate容器。
每次运行重复作业时,容器内存使用量不断增加,直到应用程序变得无响应或AWS终止容器。这是ECS上的一个16 GB的容器(大),所以它应该能够处理我扔给它的任何东西。我可以断定,一旦内存使用量达到约13 GB,它就注定要崩溃。
关键是我在本地运行此应用程序,它的内存使用率从来不会很高。我将从我的工作站和下面的容器中发布几个示例日志。
感谢您的真知灼见!
分析XML:
- 使用XmlSerializer放入JSON格式的对象
- 使用XDocument只需浏览文档
- 使用XSD文件生成类,然后使用XmlSerializer填充
编辑2019年3月5日
下面的日志来自以下代码。它不具备应用程序的全部功能,而应用程序相当复杂。此代码位于注册了Hangfire的方法中,每天运行一次。它从一个FTP站点提取XML文件,然后基本上运行下面的代码来处理这些文件。每个文件的大小不超过10 MB。工作站日志:
容器日志:
推荐答案
通过将<ServerGarbageCollection>false</ServerGarbageCollection>
添加到Web应用程序的csproj文件来禁用服务器垃圾收集(强制工作站垃圾收集)似乎会使GC更急切,从而帮助保持堆小,但非托管内存仍在缓慢增加。它最终是一个内存泄漏--静态方法通过引用将其一个参数传递回调用方,静态方法不是由GC管理的,因此每次调用此方法并提供更多要枚举的字符串时,通过引用传递的对象变得越来越大。
我删除了按引用传递,该方法现在正常返回对象(通过return
),但我仍然必须在此静态方法中调用GC.Collect()
以防止约500MB-1 GB的瞬时峰值。正常情况下,即使在生产环境中这也没有问题,因为GC确实会迅速将内存使用率降至正常水平,但是,如果这些内存峰值之一导致.NET应用程序超过内存配额,将终止ECS实例。
GC.Collect()
的调用。在您的例子中,您可能在某个地方遗漏了using
,或者您正在使用事件(不太可能),或者可能像我一样,您有一个通过引用传递某些内容的静态方法--或者不是--而那个不受GC约束的静态方法正在慢慢地泄漏。
对于禁用的&q;服务器&垃圾收集,这似乎只有在Fargate/ECS任务仅在一个vCPU上运行时才有效。有关服务器与工作站GC的详细信息,请参阅here。
Visual Studio 2022的内置性能测量工具还可以,但VS偶尔会崩溃(我的工作计算机也弱得要死),所以我最终使用了JetBrains的dotMemory,它有更好的界面和更好的快照比较功能。
这篇关于Docker中的.NET核心高内存使用率(AWS ECS Fargate)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!