2017-02-06 8 views
1

Для меня это было какое-то время, но я на 100% уверен, что это происходит и, по крайней мере, на моей машине.EF6 Утечка памяти без каких-либо причин

Я смог узнать, что именно эта небольшая часть кода вызывает утечку памяти, но все же я понятия не имею, почему.

for (int i = 0; i < 1000000; i++) 
{ 
    using (var db = new TestEntity()) 
    { 
     db.Configuration.AutoDetectChangesEnabled = false; 
     db.Configuration.ValidateOnSaveEnabled = false; 

     // If I just create new Context everything is normal. 
     // I need to request anything 
     { 
      var any = (bool)db.Test.AsNoTracking().Any(); 
     } 

     // Or more simply just in that way 
     // var any = db.Test.AsNoTracking().Any(); 

    } 
    if (i % 1000 == 0) 
    { 
     Console.WriteLine(i.ToString()); 
    } 
} 

Этот код так просто и все же я не могу видеть, что вызывает проблемы.

Я создаю новый контекст в одной итерации, а затем просто Dispose(). Моя переменная bool является локальной и никогда не используется. Я также использую Any(), который возвращает значение bool, а не ссылку на объект.

Я не соглашусь с тем, что у Garbage Collector нет времени на сбор, потому что где бы я ни заставлял его до Collect(), он все еще течет. Рекомендуется также, чтобы EF Team имела контекст как можно короче.

И еще более важно то, что эта утечка происходит/происходит в неуправляемой памяти. Результат использования ANTS Memory Profiler заключается в том, что я вижу, что есть утечка, но все же я понятия не имею, почему.

Result of ANTS Memory Profiler confirming that there is Memory Leak

Этот код приводит к StackOverflowException в EntityFramework.dll через 1 минуту (~ 200k итераций):

An unhandled exception of type 'System.StackOverflowException' occurred in EntityFramework.dll

That's basically everything I can get from this exception

В неуправляемой памяти я могу видеть ~ 200k объекты размер 8192 байт.

Это нереальный случай. Это настоящая проблема, которая останавливает меня.

Это очень простая модель того, что происходит в моем реальном программном обеспечении. Сначала нужно разобрать миллионы строк в разных форматах, а затем проверить, существует ли запись в базе данных.

Чтобы воспроизвести проблему, вам нужно: Главная программа:

using System; 
using System.Linq; 

namespace ConsoleApplication31 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var test = new TestClass(); 

      test.Test(); 
      Console.ReadLine(); 
     } 
    } 

    public class TestClass 
    { 
     public void Test() 
     { 
      try 
      { 
       for (int i = 0; i < 1000000; i++) 
       { 
        using (var db = new TestEntity()) 
        { 
         db.Configuration.AutoDetectChangesEnabled = false; 
         db.Configuration.ValidateOnSaveEnabled = false; 
         { 
          var any = (bool)db.Test.AsNoTracking().Any(); 
         } 
        } 
        if (i % 1000 == 0) 
        { 
         Console.WriteLine(i.ToString()); 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex); 
      } 
     } 
    } 
} 

И DB Модель Entity:

namespace ConsoleApplication31 
{ 
    using System.Data.Entity; 

    public partial class TestEntity : DbContext 
    { 
     public TestEntity() 
       : base("name=TestEntityConnectionString") 
     { 
     } 

     public virtual DbSet<Test> Test { get; set; } 

     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      Database.SetInitializer<TestEntity>(null); 
     } 
    } 
} 

с тестовой таблицы:

using System.ComponentModel.DataAnnotations; 

namespace ConsoleApplication31 
{ 
    public partial class Test 
    { 
      [Key] 
      [Required] 
      public long TestId { get; set; } 

      [Required] 
      public string TestName { get; set; } 

      [Required] 
      public string TestDescription { get; set; } 
     } 
} 

Мои конфигурации:

а) 4C/8T 16GB ОЗУ, Windows 10 14393 (RTM), Visual Studio 2015, SQL Server 2016

б) 2C/4T 8GB ОЗУ, точно так же система (тот же диск, подключен к другой машине)

Протестировано на версиях .NET Framework: 4.5, 4.5.2, 4.6.1, 4.6.2

Испытано на Entity Framework версии: 6.0.0, 6.1.3

Я буду признателен за любую помощь. стек

вызов сделал, когда был ~ 700MB использования памяти: [Успели Native Перехода]

System.Data.dll!SNINativeMethodWrapper.SNIReadSyncOverAsync(System.Runtime.InteropServices.SafeHandle pConn = {System.Data.SqlClient.SNIHandle}, ref System.IntPtr packet = {System.IntPtr}, int timeout) Unknown 
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync() Unknown 
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket() Unknown 
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer() Unknown 
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.TryReadByte(out byte value = 0) Unknown 
    System.Data.dll!System.Data.SqlClient.TdsParser.TryRun(System.Data.SqlClient.RunBehavior runBehavior = ReturnImmediately, System.Data.SqlClient.SqlCommand cmdHandler = {System.Data.SqlClient.SqlCommand}, System.Data.SqlClient.SqlDataReader dataStream = {System.Data.SqlClient.SqlDataReader}, System.Data.SqlClient.BulkCopySimpleResultSet bulkCopyHandler = null, System.Data.SqlClient.TdsParserStateObject stateObj, out bool dataReady = false) Unknown 
    System.Data.dll!System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() Unknown 
    System.Data.dll!System.Data.SqlClient.SqlDataReader.MetaData.get() Unknown 
    System.Data.dll!System.Data.SqlClient.SqlCommand.FinishExecuteReader(System.Data.SqlClient.SqlDataReader ds = {System.Data.SqlClient.SqlDataReader}, System.Data.SqlClient.RunBehavior runBehavior, string resetOptionsString, bool isInternal, bool forDescribeParameterEncryption) Unknown 
    System.Data.dll!System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(System.Data.CommandBehavior cmdBehavior, System.Data.SqlClient.RunBehavior runBehavior, bool returnStream, bool async, int timeout, out System.Threading.Tasks.Task task, bool asyncWrite, bool inRetry, System.Data.SqlClient.SqlDataReader ds, bool describeParameterEncryptionRequest) Unknown 
    System.Data.dll!System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior cmdBehavior, System.Data.SqlClient.RunBehavior runBehavior, bool returnStream, string method, System.Threading.Tasks.TaskCompletionSource<object> completion, int timeout, out System.Threading.Tasks.Task task, out bool usedCache, bool asyncWrite, bool inRetry) Unknown 
    System.Data.dll!System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior cmdBehavior, System.Data.SqlClient.RunBehavior runBehavior, bool returnStream, string method) Unknown 
    System.Data.dll!System.Data.SqlClient.SqlCommand.ExecuteReader(System.Data.CommandBehavior behavior, string method) Unknown 
    System.Data.dll!System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(System.Data.CommandBehavior behavior) Unknown 
    System.Data.dll!System.Data.Common.DbCommand.ExecuteReader(System.Data.CommandBehavior behavior) Unknown 
    EntityFramework.dll!System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader.AnonymousMethod__c(System.Data.Common.DbCommand t, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext<System.Data.Common.DbDataReader> c) Unknown 
    EntityFramework.dll!System.Data.Entity.Infrastructure.Interception.InternalDispatcher<System.Data.Entity.Infrastructure.Interception.IDbCommandInterceptor>.Dispatch<System.Data.Common.DbCommand, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext<System.Data.Common.DbDataReader>, System.Data.Common.DbDataReader>(System.Data.Common.DbCommand target, System.Func<System.Data.Common.DbCommand, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext<System.Data.Common.DbDataReader>, System.Data.Common.DbDataReader> operation, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext, System.Action<System.Data.Entity.Infrastructure.Interception.IDbCommandInterceptor, System.Data.Common.DbCommand, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext<System.Data.Common.DbDataReader>> executing, System.Action<System.Data.Entity.Infrastructure.Interception.IDbCommandInterceptor, System.Data.Common.DbCommand, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext<System.Data.Common.DbDataReader>> executed) Unknown 
    EntityFramework.dll!System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) Unknown 
    EntityFramework.dll!System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(System.Data.CommandBehavior behavior) Unknown 
    System.Data.dll!System.Data.Common.DbCommand.ExecuteReader(System.Data.CommandBehavior behavior) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(System.Data.Entity.Core.EntityClient.EntityCommand entityCommand, System.Data.CommandBehavior behavior) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute<bool>(System.Data.Entity.Core.Objects.ObjectContext context = {System.Data.Entity.Core.Objects.ObjectContext}, System.Data.Entity.Core.Objects.ObjectParameterCollection parameterValues) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.ObjectQuery<bool>.GetResults.AnonymousMethod__6() Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction<System.__Canon>(System.Func<System.__Canon> func, System.Data.Entity.Infrastructure.IDbExecutionStrategy executionStrategy, bool startLocalTransaction, bool releaseConnectionOnSuccess = false) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.ObjectQuery<bool>.GetResults.AnonymousMethod__5() Unknown 
    EntityFramework.SqlServer.dll!System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute<System.Data.Entity.Core.Objects.ObjectResult<bool>>(System.Func<System.Data.Entity.Core.Objects.ObjectResult<bool>> operation) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.ObjectQuery<bool>.GetResults(System.Data.Entity.Core.Objects.MergeOption? forMergeOption) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.ObjectQuery<bool>.System.Collections.Generic.IEnumerable<T>.GetEnumerator.AnonymousMethod__0() Unknown 
    EntityFramework.dll!System.Data.Entity.Internal.LazyEnumerator<bool>.MoveNext() Unknown 
    System.Core.dll!System.Linq.Enumerable.Single<bool>(System.Collections.Generic.IEnumerable<bool> source) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.GetElementFunction.AnonymousMethod__3<bool>(System.Collections.Generic.IEnumerable<bool> sequence) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle<bool>(System.Collections.Generic.IEnumerable<bool> query, System.Linq.Expressions.Expression queryRoot) Unknown 
    EntityFramework.dll!System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.Execute<bool>(System.Linq.Expressions.Expression expression) Unknown 
    EntityFramework.dll!System.Data.Entity.Internal.Linq.DbQueryProvider.Execute<bool>(System.Linq.Expressions.Expression expression) Unknown 
    System.Core.dll!System.Linq.Queryable.Any<ConsoleApplication31.Test>(System.Linq.IQueryable<ConsoleApplication31.Test> source) Unknown 
> ConsoleApplication31.exe!ConsoleApplication31.TestClass.Test() Line 31 C# 
    ConsoleApplication31.exe!ConsoleApplication31.Program.Main(string[] args = {string[0]}) Line 12 C# 
    [Native to Managed Transition] 
    [Managed to Native Transition] 
    mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) Unknown 
    Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() Unknown 
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) Unknown 
    mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown 
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown 
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Unknown 
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() Unknown 
+0

Попробуйте создать экземпляр вашего 'TestEntity' вне цикла. Вы создаете множество примеров очень быстро. – Dispersia

+0

@Dispersia: Я действительно пробовал это, но это не помогает. – Wiktor

+0

Это действительно не имеет смысла. «StackOverflowException» обычно возникает, когда [слишком много вложенных вызовов метода] (https://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx). Можете ли вы прервать приложение на полпути и проверить стек вызовов? – DavidG

ответ

0

Я до сих пор понятия не имею, почему этот вопрос происходя, но теперь я знаю, что это связано с моей Sql Установка сервера.

Когда я использую сервер Sql, установленный в Hyper-V, все кажется, что все в порядке.

Так же быстро, как я меняю строку подключения, чтобы указать на экземпляр сервера localhost Sql, тогда у меня есть эта странная утечка.

На данный момент это какое-то разрешение для меня, по крайней мере, я могу двигаться дальше.

+0

Может ли это быть связано с тем, как ваша клиентская библиотека подключается к SQL-серверу? Есть больше вариантов локального SQL-сервера, чем для удаленного, например, именованных каналов. Вы сказали, что утечки происходят в неуправляемой памяти, поэтому я думаю, что это может быть вызвано ошибкой, связанной с подключением. Попробуйте изменить ConnectionString, чтобы отключить или изменить пул соединений и посмотреть, не изменило ли это что-либо. Попробуйте указать, что соединение должно происходить с tcp. [msdn doc] (https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.connectionstring (v = vs.110) .aspx) –

 Смежные вопросы

  • Нет связанных вопросов^_^