2016-11-12 98 views
1

我使用EF6與SQLite數據庫。我爲每個請求創建和處理對象DBContext,但想要緩存SQLiteConnection對象,因此數據庫會保留在內存中。看起來EF在這種情況下會泄漏內存。實體框架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); 

這是一個已知的問題?有更好的解決方法嗎?

回答

1

我有同樣的問題。在EntityConnection上調用Dispose()似乎可以解決問題。

public class CustomDbContext : DbContext 
{ 
    private EntityConnection _entityConnection; 

    public CustomDbContext(EntityConnection connection) 
     : base(connection, false) 
    { 
     _entityConnection = connection; 
    } 

    protected override void Dispose(bool disposing) 
    { 
     base.Dispose(disposing); 
     if (disposing && _entityConnection != null) 
      _entityConnection.Dispose(); 
    } 
}