【问题标题】:Entity framework memory not released实体框架内存未释放
【发布时间】:2014-01-27 11:09:25
【问题描述】:

我正在使用一个非常简单的 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:&lt;port&gt; -uri:/home/index/ -threads:30 -loop:5000)。在性能监视器中,我看到第 2 代堆稳步增长。如果我使用较小的循环值(例如 500),则大小会增长,直到 tinyget 停止。然后堆大小保持不变(至少 20 分钟,之后我停止了服务器)。

我做错了什么?

编辑

所以我尝试了 Simon Mouriers 的建议并省略了 EF 代码。那我就没有记忆问题了。所以我想,也许如果我使用 Release 而不是 Debug,它会有所作为。它做到了!一段时间后内存被释放,我可以在网站上放置高负载。然后我切换回调试,看看我是否可以获得更多信息,并且......即使在调试模式下也没有问题了。 FML,我花了一天的时间,现在我无法再复制它了。

【问题讨论】:

  • 我会说你没有做错任何事,这很可能是 EF 过度膨胀的代码库的问题。
  • 我也找不到什么问题,只是觉得内存使用率没有下降很奇怪。
  • 大概用int count = 0; return View(count); 替换代码并不能证明表明它的EF 不是其他东西的问题?
  • 您可能偶然发现了 EF 6 中的错误,请尝试降级到 EF 5。如果您可以确认这是 EF 5 和 6 之间的更改,我想 M$ 会很高兴听到来自你(参考。entityframework.codeplex.com/workitem/1605 - 最后的 cmets)
  • 看起来你可能会遇到这个问题:entityframework.codeplex.com/workitem/1605

标签: c# entity-framework entity-framework-6


【解决方案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.
}

在没有专门覆盖对 dispose 的调用的情况下,using 语句只会针对基类调用 Dispose(),而您需要对父类和基类进行 dispose。

【讨论】:

    【解决方案2】:

    这可能不是正确的答案,但我建议让您的上下文由 IoC 容器管理。并使用 TrasientScope 或 PerHttpRequest 范围添加它(由于 ioc 容器语法种类繁多,未提供示例)。如果你想要一个具体的例子,请回复你想要的DI

    【讨论】:

    • 在显示的代码中,上下文是每个请求的范围。这是我能想到的最简单的例子,DI 只会在这种情况下复杂化。
    • 那么它一定是一个没有被释放的资源,因此它的父对象不会被收集。 GC 只收集没有引用的资源。您必须查看未处理的内容。我更喜欢使用 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(),因为它会干扰垃圾收集机制。

    【讨论】:

    • 这充其量只是治标不治本,而忽略了根本问题。问题必须是 Dispose 模式问题或其他形式的悬空引用。这可能是 EF 中的错误。它甚至可能是 .NET 本身横盘整理的一些晦涩的问题。请注意,OP 表示在构建 Release 然后切换回 Debug 后,无法重现该问题。
    【解决方案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

    【讨论】:

    • 如果打开,您的代码将关闭与 db 的连接。没有其他的。但问题在于托管内存的内存使用情况。
    • 是的,我现在可以看到.. @KirillBestemyanov msdn.microsoft.com/en-us/library/vstudio/…
    【解决方案5】:

    我认为您的代码没有任何问题。也许这可能是底层 ADO.NET 提供程序的问题。你用的是哪个数据库?

    我记得在一些单元测试中遇到了问题,这些问题没有发布我最终用这段代码解决的 SQLite 数据库文件(在我的 DbContext 类中)

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

    可能不相关,但我会试一试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-26
      相关资源
      最近更新 更多