Если я просто просматриваю некоторые страницы в приложении, он сидит около 500 МБ. Многие из этих страниц обращаются к базе данных, но на данный момент у меня есть примерно одна пара строк для 10 таблиц, в основном хранящая строки и некоторые небольшие значки размером менее 50 КБ.
Реальная проблема возникает, когда я загружаю файл. Файл составляет около 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.
Вот несколько скриншотов из Профайлера:
Я считаю, что это может быть проблемой, или я иду по неверному пути. Почему Find()
использовать 300 МБ?
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);
}
}
ИЗМЕНИТЬ 2:
Я запускал dotMemory для различных сценариев, и это то, что я получил.
Красные круги указывают на то, что иногда на одной странице посещают несколько повышений и капель. Синий круг указывает на загрузку 40 МБ файла. Зеленый круг указывает загрузку 140 МБ файла. Более того, время от времени использование памяти продолжает расти еще на несколько секунд даже после мгновенной загрузки страницы.