Я использую EF6 с базой данных SQLite. Я создаю и удаляю объекты DBContext
для каждого запроса, но хочу, чтобы я кэшировал объекты SQLiteConnection
, поэтому база данных остается в кэше в памяти. Похоже, что EF утечки памяти в этих обстоятельствах.Утечка памяти Entity Framework 6
Вот минимальный рабочий пример:
class Program
{
static void Main(string[] args)
{
// use one connection for the lifetime of the application
using (var conn = new System.Data.SQLite.SQLiteConnection("Data Source=:MEMORY:"))
{
// create sample DB
conn.Open();
using (var context = new MyContext(conn, false))
context.Database.ExecuteSqlCommand("CREATE TABLE SomeTable(Id INTEGER PRIMARY KEY AUTOINCREMENT)");
while (true)
{
// access database
using (var context = new MyContext(conn, false))
{
var x = System.Linq.Enumerable.Count(context.SomeTable);
}
// show memory usage
System.Console.Write("{0:0,0} Bytes \r", System.GC.GetTotalMemory(false));
}
}
}
}
class MyContext : System.Data.Entity.DbContext
{
public MyContext(System.Data.Common.DbConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection, contextOwnsConnection)
{ }
public System.Data.Entity.DbSet<SomeTableRow> SomeTable { get; set; }
}
[System.ComponentModel.DataAnnotations.Schema.Table("SomeTable")]
class SomeTableRow
{
public int Id { get; set; }
}
Если я запускаю это, использование памяти процесс продолжает расти.
Я думаю, проблема в том, что System.Data.Entity.Core.EntityClient.EntityConnection
подписывается на событие StateChange
на объекте соединения и никогда не отзывается от него.
Мой (очень некрасиво) обходной путь, чтобы вручную «очистить» поле StateChange
события после каждого использования, как это:
conn
.GetType()
.GetField("StateChange", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.SetValue(conn, null);
Это известная проблема? Есть ли лучшее обходное решение?