MVC ASP.NET正在使用大量内存 [英] MVC ASP.NET is using a lot of memory

查看:178
本文介绍了MVC ASP.NET正在使用大量内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我仅浏览该应用程序上的某些页面,它的大小约为500MB.这些页面中的许多页面都访问数据库,但是在此时,我大约只有几行,每行10个表,主要存储字符串和一些小于50KB的小图标.

If I just browse some pages on the app, it sits at around 500MB. Many of these pages access the database but at this point in time, I only have roughly a couple of rows each for 10 tables, mostly storing strings and some small icons that are less than 50KB.

真正的问题是当我下载文件时发生的.该文件大约为140MB,并以 varbinary(MAX)的形式存储在数据库中.内存使用量突然上升到一秒钟的1.3GB,然后又下降到1GB.该操作的代码在这里:

The real problem occurs when when I download a file. The file is roughly 140MB and is stored as a varbinary(MAX) in the database. The memory usage suddenly rises to 1.3GB for a split second and then falls back to 1GB. The code for that action is here:

public ActionResult DownloadIpa(int buildId)
{
    var build = _unitOfWork.Repository<Build>().GetById(buildId);
    var buildFiles = _unitOfWork.Repository<BuildFiles>().GetById(buildId);
    if (buildFiles == null)
    {
        throw new HttpException(404, "Item not found");
    }

    var app = _unitOfWork.Repository<App>().GetById(build.AppId);
    var fileName = app.Name + ".ipa";

    app.Downloads++;
    _unitOfWork.Repository<App>().Update(app);
    _unitOfWork.Save();

    return DownloadFile(buildFiles.Ipa, fileName);
}

private ActionResult DownloadFile(byte[] file, string fileName, string type = "application/octet-stream")
{
    if (file == null)
    {
        throw new HttpException(500, "Empty file");
    }

    if (fileName.Equals(""))
    {
        throw new HttpException(500, "No name");
    }

    return File(file, type, fileName);            
}

在我的本地计算机上,如果我什么也不做,则内存使用量将保持在1GB.然后,如果我返回并导航到某些页面,它将回落到500MB.

On my local computer, If I don't do anything, the memory usage stays at 1GB. If I then go back and navigate to some pages, it falls back down to 500MB.

在部署服务器上,无论我做什么,首次下载后它都保持在1.6GB.我可以通过不断下载文件直到其达到3GB(然后回落到1.6GB)来强制增加内存使用量.

On the deployment server, it stays at 1.6GB after the first download no matter what I do. I can force the memory usage to increase by continually downloading files until it reaches 3GB, where it drops back down to 1.6GB.

在每个控制器中,我都这样重写了 Dispose()方法:

In every controller, I have overriden the Dispose() method as so:

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

这是指:

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

public void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing)
        {
            _context.Dispose();
        }
    }

    _disposed = true;
}

因此,每次布置控制器时,都应布置我的工作单元.我正在使用Unity,并在Heirarchical Lifetime Manager中注册了工作单元.

So my unit of work should be disposed every time the controller is disposed. I am using Unity and I register the unit of work with a Heirarchical Lifetime Manager.

以下是Profiler的一些屏幕截图:

Here are a few of screenshots from the Profiler:

我认为这可能是问题所在,或者我走错了路.为什么 Find()使用300MB?

I believe this could be the problem or I am going down the wrong track. Why would Find() use 300MB?

存储库:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
    internal IDbContext Context;
    internal IDbSet<TEntity> DbSet;

    public Repository(IDbContext context)
    {
        Context = context;
        DbSet = Context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> GetAll()
    {            
        return DbSet.ToList();
    }

    public virtual TEntity GetById(object id)
    {
        return DbSet.Find(id);
    }

    public TEntity GetSingle(Expression<Func<TEntity, bool>> predicate)
    {
        return DbSet.Where(predicate).SingleOrDefault();
    }

    public virtual RepositoryQuery<TEntity> Query()
    {
        return new RepositoryQuery<TEntity>(this);
    }

    internal IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        List<Expression<Func<TEntity, object>>> includeProperties = null)
    {
        IQueryable<TEntity> query = DbSet;

        if (includeProperties != null)
        {
            includeProperties.ForEach(i => query.Include(i));
        }

        if (filter != null)
        {
            query = query.Where(filter);
        }

        if (orderBy != null)
        {
            query = orderBy(query);
        }

        return query.ToList();
    }

    public virtual void Insert(TEntity entity)
    {
        DbSet.Add(entity);
    }

    public virtual void Update(TEntity entity)
    {
        DbSet.Attach(entity);
        Context.Entry(entity).State = EntityState.Modified;
    }

    public virtual void Delete(object id)
    {
        var entity = DbSet.Find(id);

        Delete(entity);
    }

    public virtual void Delete(TEntity entity)
    {
        if (Context.Entry(entity).State == EntityState.Detached)
        {
            DbSet.Attach(entity);
        }

        DbSet.Remove(entity);
    }
}

我为各种情况运行了dotMemory,这就是我所得到的.

I ran dotMemory for a variety of scenarios and this is what I got.

红色圆圈表示有时一页访问会发生多次上升和下降.蓝色圆圈表示下载了40MB的文件.绿色圆圈表示下载140MB文件.此外,在很多情况下,即使页面立即加载,内存使用量也会持续增加几秒钟.

The red circles indicate that sometimes there are multiple rises and drops happening on one page visit. The blue circle indicates download of a 40MB file. The green circle indicates download of 140MB file. Furthermore, a lot of the time, the memory usage keeps on increasing for a few more seconds even after the page has instantly loaded.

推荐答案

将GC.Collect()添加到Dispose方法中以进行测试.如果泄漏仍然存在,那就是真正的泄漏.如果消失,则只是延迟了GC.

Add a GC.Collect() to the Dispose method for testing purposes. If the leak stays it is a real leak. If it vanishes it was just delayed GC.

您这样做并说:

@usr的内存使用量现在几乎达到600MB.所以真的只是耽搁了吗?

@usr Memory usage now hardly reaches 600MB. So really just delayed?

很显然,如果GC.Collect删除了您担心的内存,则不会发生内存泄漏.如果您想确定,请运行10次测试.内存使用率应该稳定.

Clearly, there is no memory leak if GC.Collect removes the memory that you were worried about. If you want to make really sure, run your test 10 times. Memory usage should be stable.

在单个大块中处理此类大文件时,随着文件通过不同的组件和框架,可能导致内存使用量成倍增长.切换到流媒体方法可能是个好主意.

Processing such big files in single chunks can lead to multiplied memory usage as the file travels through the different components and frameworks. It can be a good idea to switch to a streaming approach.

这篇关于MVC ASP.NET正在使用大量内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆