Подтвердить что ты не робот

Не удалось освободить фрейм-память Entity

Я использую очень простое приложение asp.net mvc с Entity Framework 6.0.2,.Net 4.5.1:

public class HomeController : Controller
{
   public ActionResult Index()
   {
      int count;
      using (var db = new LocalContext())
      {
         count = db.Counters.Count();
      }
      return View(count);
   }
}

public class Counter
{
   public int Id { get; set; }
}

public class LocalContext : DbContext
{
   public DbSet<Counter> Counters { get; set; }
}

Если я выполняю нагрузку на нем, я в конечном итоге получаю исключение из памяти. (tinyget -srv:localhost -port:<port> -uri:/home/index/ -threads:30 -loop:5000). В мониторе производительности я вижу, что поколение 2 Heap постоянно растет. Если я использую меньшее значение цикла (скажем, 500), размер увеличивается до тех пор, пока tinyget не остановится. Затем размер кучи остается неизменным (по крайней мере 20 минут, после чего я остановил сервер).

Что я делаю неправильно?

ИЗМЕНИТЬ

Итак, я попробовал предложение Саймона Моурье и отказался от кода EF. Тогда у меня нет проблем с памятью. Поэтому я подумал, может быть, если я использую Release вместо Debug, это будет иметь значение. И это было! Через некоторое время память была выпущена, и я мог разместить большую нагрузку на сайте. Затем я переключился обратно в Debug, чтобы узнать, могу ли я получить больше информации и... даже в режиме отладки больше нет проблем. FML, я работал над этим днем, и теперь я больше не могу воспроизвести его.

4b9b3361

Ответ 1

В вашем случае внутренне управляемый класс, который наследует от DbContext, должен затем реализовать IDisposable и внутри LocalContext добавить следующее:

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

protected virtual void Dispose(bool disposing)
{
     if (disposing)
     {
        // Manage any native resources.
     }
   //Handle any other cleanup.
}

Без особого переопределения вызова для распоряжения оператор using будет только вызывать Dispose() для базового класса, тогда как вам нужно избавиться от родительского и базового.

Ответ 2

Это может быть не правильный ответ, но я предлагаю сохранить ваш контекст, управляемый контейнером IoC. И добавьте его с областью TrasientScope или PerHttpRequest (пример не указан из-за большой разновидности синтаксиса контейнера ioc). Если вам нужен конкретный пример, ответьте, для чего вы хотите

Ответ 3

Собственно, OutOfMemotyException является нормальным в этой ситуации, поскольку сборщик мусора не возникает сразу после того, как вы закончили с объектом. В этом случае вам нужно использовать GC.Collect() для выполнения коллекции во всех поколениях памяти и немедленно вернуть всю незащищенную память.

public class HomeController : Controller
{
   public ActionResult Index()
   {
      int count;
      using (var db = new LocalContext())
      {
         count = db.Counters.Count();
      }

      GC.Collect();
      return View(count);
   }
}

Обратите внимание, что вы не должны использовать GC.Collect() в производственном коде, так как он мешает механизму сбора мусора.

Ответ 4

Я хотел бы создать соединение класса с БД..

public class DBconnection : IDisposable
{
    private ChatEntities _db = new ChatEntities();

    protected ChatEntities Db {
        get { return _db; }
    }

    public void Dispose()
    {
        if (_db != null)
        {
            _db.Dispose();
        }
    }
}

Затем, когда вы хотите подключиться и манипулировать.. Позволяет называть его классом DBlogic..

public class DBlogic : DBconnection
{
       internal void WriteToDB(String str){
          //Do something ...

          Db.SaveChanges();
        }
}

Это приведет к тому, что Dispose опустит ресурсы.. плюс его очиститель.. по крайней мере для моих глаз: D

Ответ 5

Я не вижу ничего плохого в вашем коде. Возможно, это может быть проблемой с базовым поставщиком ADO.NET. Какую базу данных вы используете?

Я помню, что у меня были проблемы с некоторыми unit test, которые не выпускали файлы базы данных SQLite, которые я в конечном итоге решил с помощью этого кода (в моем классе DbContext)

public class LocalContext : DbContext
{
    protected override void Dispose(bool disposing)
    {
        var connection = this.Database.Connection;
        base.Dispose(disposing);
        connection.Dispose();
    }
}

Может быть несвязанным, но я бы попробовал.