简体   繁体   English

EF6内存泄漏没有任何理由

[英]EF6 Memory leak without any reason

It's been a while for me to find this issue but I am 100% sure that it's happening and at least on my machine. 我找到这个问题已经有一段时间了,但我100%确定它正在发生,至少在我的机器上。

I was able to found out that just this small piece of code is causing of memory leaks, but still I have no idea why. 我能够发现只是这一小段代码导致内存泄漏,但我仍然不知道为什么。

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());
    }
}

This code is so simply and still I am unable to see what is causing the issues. 这段代码很简单,我仍然无法看到导致问题的原因。

I am creating new Context in single iteration and then just Dispose() it. 我在单次迭代中创建新的Context,然后只是Dispose()它。 My bool variable is local and is never used. 我的bool变量是本地的,从不使用。 I am also using Any() which is returning bool value and not reference to object. 我也使用Any()返回bool值而不是对象的引用。

I will not agree to that Garbage Collector have no time to collect because wherever I will force him to Collect() it's still leaking. 我不同意Garbage Collector没有时间收集,因为无论我何时强迫他Collect()它仍然在泄漏。 It's also recommended by EF Team to have Context for as short time as possible. EF团队还建议尽可能短时间使用Context。

And more important is that this leak is going/happening into unmanaged memory. 更重要的是,这种泄漏正在/发生在非托管内存中。 The result of using ANTS Memory Profiler is that I can see that there is leak but still I have no idea why. 使用ANTS Memory Profiler的结果是我可以看到有泄漏,但我仍然不知道为什么。

ANTS Memory Profiler确认存在内存泄漏的结果

This code is resulting in StackOverflowException in EntityFramework.dll after 1 minute ( ~200k iterations): 此代码在1分钟(~200k迭代)后导致EntityFramework.dll中出现StackOverflowException

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

这基本上就是我从这个例外中得到的一切

In unmanaged memory I can see ~200k objects of size 8192 bytes. 在非托管内存中,我可以看到大约8192字节的~200k对象。

It's not unrealistic case. 这不是不现实的情况。 It's the real problem which is stopping me. 这是阻止我的真正问题。

This is very basic model of what is happening in my real software. 这是我真实软件中发生的事情的基本模型。 I need to parse millions of lines in different format at first and then check if record exists in database. 我需要先解析数百万行不同格式的行,然后检查数据库中是否存在记录。

To reproduce the issue you need: Main program: 重现您需要的问题:主程序:

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);
            }
        }
    }
}

And DB Model Entity : 和DB模型实体:

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);
        }
    }
}

With Test Table: 有测试表:

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; }
        }
}

My configurations: 我的配置:

a) 4C/8T 16GB RAM, Windows 10 14393 (RTM), Visual Studio 2015, Sql Server 2016 a)4C / 8T 16GB RAM,Windows 10 14393(RTM),Visual Studio 2015,Sql Server 2016

b) 2C/4T 8GB RAM, exactly the same system (the same disk, connected to other machine ) b)2C / 4T 8GB RAM,完全相同的系统(相同的磁盘,连接到其他机器)

Tested on .NET Framework versions: 4.5, 4.5.2, 4.6.1, 4.6.2 在.NET Framework版本上测试:4.5,4.5.2,4.6.1,4.6.2

Tested on Entity Framework versions: 6.0.0, 6.1.3 在Entity Framework版本上测试:6.0.0,6.1.3

I will appreciate any help. 我将不胜感激任何帮助。

Call stack made when there was ~700MB of memory usage: [Managed to Native Transition] 当有大约700MB的内存使用时调用堆栈:[管理到本机转换]

    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

I still have no idea why this issue is occuring but now I know that it's related to my Sql Server installation. 我仍然不知道为什么会出现这个问题,但现在我知道它与我的Sql Server安装有关。

When I am using Sql Server installed in Hyper-V then everything seems to be fine. 当我使用Hyper-V中安装的Sql Server时,一切似乎都没问题。

As fast as I change connection string to point to my localhost Sql server instance then I've got this weird leak. 当我将连接字符串更改为指向我的localhost Sql server实例时,我就会遇到这种奇怪的泄漏。

For now this is some kind of sollution for me, at least I can move on. 现在这对我来说是一种解决方案,至少我可以继续前进。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM