Если я просто просматриваю некоторые страницы приложения, он находится примерно в 500 МБ. Многие из этих страниц обращаются к базе данных, но на данный момент у меня есть только примерно пара строк для 10 таблиц, в основном для хранения строк и небольших значков размером менее 50 КБ.MVC ASP.NET использует много памяти
Настоящая проблема возникает, когда я загружаю файл. Файл составляет примерно 140 МБ и хранится как varbinary(MAX)
в базе данных. Использование памяти внезапно возрастает до 1,3 ГБ на долю секунды, а затем падает до 1 ГБ. Код для этого действия находится здесь:
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);
}
На моем локальном компьютере, если я ничего не делаю, использование памяти составляет 1 ГБ. Если я затем вернусь и перейду к некоторым страницам, он опустится до 500 МБ.
На сервере развертывания он остается на 1,6 ГБ после первой загрузки независимо от того, что я делаю. Я могу заставить использование памяти увеличиваться, постоянно загружая файлы, пока не достигнет 3 ГБ, где он упадет до 1,6 ГБ.
В каждом контроллере, я переопределен метод Dispose()
в качестве так:
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.
Вот несколько скриншотов из Profiler:
Я считаю, что это может быть проблема или я иду по неверному пути. Зачем использовать Find()
300MB?
EDIT:
Repository:
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);
}
}
EDIT 2:
Я побежал dotMemory для различных сценариев, и это то, что я получил.
красные круги показывают, что иногда несколько поднимается и падает происходит на одной странице визита. Синий круг указывает на загрузку 40 МБ файла. Зеленый круг указывает загрузку 140 МБ файла. Кроме того, время от времени использование памяти продолжает расти еще на несколько секунд даже после мгновенной загрузки страницы.
Try в JetBrains dotMemory 4. 1 beta www.jetbrains.com/dotmemory/download – leppie
Не могли бы вы разместить весь репозиторий? (Некоторые люди думают, что весь шаблон репозитория - это анти-шаблон, и я один из них, но это не так). У меня подозрительное подозрение '_unitOfWork.Repository() .Update (app);' может привести к загрузке всего DbSet, но я не вижу его из кода, который вы опубликовали. –
Martijn
Если вы уменьшили размер файла в два раза, снизится ли использование памяти пиковой памяти? Это поможет вам разобраться, является ли это сам файл или код, вызывающий извлечение файла, вызывающего проблему. – krisdyson