ASP.NET MVC 和 EF Code First 内存使用情况

17

我有一个基于ASP.NET MVC 3构建的应用程序,使用SQL CE进行存储和EF CTP 5进行数据访问。

我将此站点部署到共享主机上,发现它在命中其(专用)应用程序池设置的100mb限制时不断被回收。

在发布模式下运行的网站大约使用110mb RAM。

我尝试使用SQL Server Express而不是CE,但效果不大。

唯一显著的区别是当我完全删除了EF(使用虚拟repo)时。这使内存使用量降低了30mb-40mb。空白MVC模板大约使用20mb左右,所以我认为这还不错?

是否有“标准”ASP.NET MVC应用程序的基准测试?

如果能知道其他EF CTP用户的内存利用率以及一些内存分析工具(最好是免费的),那就太好了。

值得一提的是,我如何处理EF ObjectContext的生命周期。我正在使用每个请求的会话,并使用StructureMap实例化ObjectContext:

For<IDbContext>().HttpContextScoped().Use(ctx => new MyContext("MyConnStringName"));

非常感谢 Ben


1
在我看来,你的应用程序池只有100MB是微不足道的。 - Kirk Woll
这就是我想的,但在我有什么可对标的东西之前,我真的没有理由回到主机那里。 - Ben Foster
这取决于你支付了多少费用。显然,一个每月10美元的共享主机公司不会为这样的经济账户分配太多资源。另一方面,如果你每月支付约50美元,你应该能够获得大约1GB的内存,这将是足够的。 - Kirk Woll
@Kirk,我的主要关注点是这些限制对于任何asp.net应用程序来说似乎都不现实。我不想点名批评,但这个账户每月只有25美元,而且该公司非常强调开源项目(如nopCommerce和mojoPortal)的广告。通过对这两个应用程序的原始安装进行分析,您会发现100mb的限制完全不现实,特别是如果这还包括加载CLR所使用的内存。 - Ben Foster
我有同样的问题和限制,也许是同样的主机?是的,我拥有的计划肯定不是每月10美元,他们宣传“无限制”的一切,直到你了解到他们设置了100MB的不现实的限制。@Ben,我测量了我的MVC应用程序,与你的数字相匹配,使用EF超过100MB,没有EF则少于40MB,我想唯一的选择是获取虚拟服务器。 - Nestor
2个回答

28

我们确实成功地显著减少了内存占用。现在,IIS工作进程的内存占用量约为50MB,而之前超过100MB。

以下是一些帮助我们实现这一目标的方法:

  • 检查基本设置。确保您在发布模式下编译,并在web.config中将编译调试设置为false。很容易忘记这些事情。
  • 使用DEBUG符号进行诊断代码。例如,当使用NHProf等工具时,就会出现这种情况(是的,我之前也被抓了)。最简单的方法是将这样的代码包装在#if DEBUG指令中,以确保它不会编译到应用程序的发布版本中。
  • 不要忘记SQL。ORM使得忽略应用程序与数据库交互变得太容易。使用SQL Profiler或EFProf / NHProf等工具可以显示确切的操作过程。在EF的情况下,您可能会感到有点不舒服,特别是如果您大量使用延迟加载。一旦您克服了这一点,就可以开始优化(参见下面的要点)。
  • 延迟加载很方便,但不应在MVC视图中使用(在我看来)。这是我们高内存使用率的根本原因之一。我们网站的主页由于延迟加载(SELECT N+1)而创建了59个单独的查询。创建此页面的特定视图模型并急切地加载所需的关联后,我们只需要执行6个查询,时间减半。
  • 设计模式是为了指导您,而不是支配应用程序的开发。我倾向于遵循DDD方法。在这种情况下,我实际上不想在我的领域模型中公开外键。但是,由于EF处理多对一关联的方式并不像NH那样好(它会发出另一个查询来获取我们已经在内存中拥有的对象的外键),因此我最终得到了额外的查询(每个对象)。在这种情况下,我决定可以容忍一些代码气味(在我的模型中包含FK),以改善性能。
  • 一个常见的“解决方案”是将缓存用于性能问题。在制定缓存策略之前,重要的是要确定真正的问题。我本可以将输出缓存应用于我们的主页(请参阅下面的注释),但这并不能改变当缓存过期时我有59个查询命中我的数据库这一事实。

关于输出缓存的注意事项: 当ASP.NET MVC首次发布时,我们能够进行甜甜圈缓存,即除了特定区域外缓存整个页面。现在无法实现这一点,如果页面中有用户特定信息,则输出缓存几乎没有用处。例如,我们在网站的导航菜单中有登录状态。这意味着我不能使用输出缓存来缓存页面,因为它也会缓存登录状态。

最终,没有硬性规定如何优化应用程序。我们应用程序性能的最大改进是当我们停止使用ORM构建关联(用于我们网站的公共部分)并手动加载它们到我们的视图模型中时。我们无法使用EF来急切地加载它们,因为关联太多了(导致杂乱无章的UNION查询)。

一个例子是我们的标记机制。像BlogPost和Project这样的实体可以被标记。标记和可标记实体之间存在多对多的关系。在我们的情况下,更好的方法是检索所有标记并将它们缓存起来。然后,我们创建了一个linq投影来缓存我们可标记实体的关联键(例如ProjectId / TagId)。当为我们的页面创建视图模型时,我们可以构建每个可标记实体的标记,而不需要访问数据库。同样,这是特定于我们的应用程序,但它在性能和降低内存使用方面产生了巨大的改进。

我们沿途使用的一些资源/工具:

虽然我们确实进行了改进,以使我们符合托管公司(Arvixe)的应用程序池限制,但我觉得有责任告知那些正在查看他们的Windows经销商计划的人,这样的限制已经存在(因为Arvixe在广告计划时没有提到这一点)。所以当某些事情看起来太好以至于不可思议(无限制x、y、z),通常就是如此。


这些对于任何MVC开发者来说都是非常棒的技巧! - Alexandre Brisebois
非常好且文档详尽。我猜我们所有人都来自于Arvixe的问题,我们只能建议其他人在签约Arvixe之前检查一下,是的,他们承诺无限制的x、y、z...无言以对。 - Nestor

0

这很有可能。不过文章还是很有用的。 - Ben Foster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接