ASP.NET应用程序的高内存使用率

时间:2015-02-03 14:31:01

标签: c# asp.net asp.net-mvc iis asp.net-web-api

我们的一些ASP.Net应用程序存在问题。我们的一些应用程序从一开始就声称拥有大量内存作为其工作集。

在我们的2个webfarm服务器(每个4GB的RAM)上运行多个应用程序。我们有一个稳定的环境,大约1.2gb的内存空闲。

然后我们添加一个MVC5 + WebApi v2 +实体框架应用程序,立即声称1 + gb作为工作集内存,而实际只使用约300mb。这导致其他应用程序抱怨没有足够的内存。

我们已经尝试过设置虚拟内存限制和私有内存限制,但没有任何效果。如果我们将其设置为大约500mb,则应用程序仍然使用或多或少相同的内存量(超过500),并且似乎不尊重已实施的限制。

作为参考,我用一个空的MVC5项目(VS2013模板)测试了这个,这已经声称300mb的内存,而只使用大约10mb。

将应用程序设置为32位应用程序似乎会对缩小工作集的大小产生一些影响。

有没有办法减少工作集的大小,或对其大小强制实施硬限制?

编辑: 在使用Web Api v2和Entity Framework为项目使用大量内存的情况下,我的API控制器如下所示:

namespace Foo.Api
{
public class BarController : ApiController
{
    private FooContext db = new FooContext(); 

    public IQueryable<Bar> GetBar(string bla)
    {
        return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year);
    }
}

因为他们看到我能找到的大多数教程(包括来自微软的教程)。由于LINQ延迟加载,此处使用using不起作用。如果我在任何地方添加了ToList(未经测试),它可以工作,但这会产生任何其他影响吗?

EDIT2: 如果我这样做就行了

namespace Foo.Api
{
public class BarController : ApiController
{
    public List<Bar> GetBar(string bla)
    {
        using(FooContext db = new FooContext){
           return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year).ToList();
        }
    }
}

ToList()是否对api的性能有任何影响? (我知道我不能像IQueryable一样廉价地继续查询)

EDIT3: 我注意到它的应用程序的私有工作集非常高。有没有办法限制这个? (不引起不断循环)

Edit4: 据我所知,我在每个APIController都有一个Dispose。我的前端只是一些简单的MVC控制器,但对于大部分.cshtml和javascript(角度)文件。

我们有另一个应用程序,只是常规的mvc,有两个模型和一些简单的视图(没有数据库,或其他可能被泄露的外部资源),这也消耗了多达4-500mb的内存。如果我对它进行分析,我看不到任何指示内存泄漏的内容,我确实看到实际上只使用了10或20 mb,其余的是未分配的非托管内存(但是是私有内存工作集的一部分,所以这个应用程序声称,任何其他人无法使用。)

2 个答案:

答案 0 :(得分:3)

我的一些应用程序遇到了类似的问题。我能够通过将一次性数据库资源包装在using子句中来正确关闭它来解决问题。

对于Entity Framework,这意味着确保在每次请求后始终关闭您的上下文。应在请求之间处理连接。

using (var db = new MyEFContext())
{
   // Execute queries here
   var query = from u as db.User
               where u.UserId = 1234
               select u.Name;

   // Execute the query.
   return query.ToList();

   // This bracket will dispose the context properly.
}

您可能需要将上下文包装到请求缓存上下文的服务中,以便在整个请求期间使其保持活动状态,并在完成后将其处置。

或者,如果使用整个控制器like in the MSDN examples具有单个上下文的模式,请确保覆盖Dispose(bool)方法,如示例here

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        db.Dispose();
    }
    base.Dispose(disposing);
}

所以你的控制器(从上面看)应该是这样的:

namespace Foo.Api
{
    public class BarController : ApiController
    {
        private FooContext db = new FooContext(); 

        public IQueryable<Bar> GetBar(string bla)
        {
             return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year);
        }

        // WebApi 2 will call this automatically after each 
        // request. You need this to ensure your context is disposed
        // and the memory it is using is freed when your app does garbage 
        // collection.
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

我看到的行为是应用程序会消耗大量内存,但它可能会垃圾收集足够的内存以防止它获得OutOfMemoryException。这使得很难找到问题,但是处理数据库资源解决了这个问题。其中一个应用程序用于悬停在大约600 MB的RAM使用率,现在它徘徊在75 MB左右。

但是这个建议不仅适用于数据库连接。 如果遇到内存泄漏,那么实现IDisposable的任何类都应该是可疑的。但既然你提到你正在使用EntityFramework,那么它最有可能被怀疑。

答案 1 :(得分:1)

删除所有Telerik Kendo MVC引用(dll等)修复了我们的问题。如果我们没有运行应用程序,我们所有的内存问题都消失了,我们看到正常的内存使用。

基本上:它是一个导致高内存使用的外部库。