EF 6 连接池和存储的查询字符串 RAM 泄漏

Posted

技术标签:

【中文标题】EF 6 连接池和存储的查询字符串 RAM 泄漏【英文标题】:EF 6 Connection pool and stored query strings RAM leak 【发布时间】:2020-07-01 02:09:41 【问题描述】:

我有 2 个问题。

第一个是连接池和(OracleConnectionImpl)随着时间的推移稳步增长,直到它达到内存不足异常。正如您在图片上看到的,它在运行 3-4 小时后有 90 MB。

我到处都在使用短暂的上下文,但它会不断增长并且永远不会自行清除。有什么办法可以清除吗?

第二个是 EF 随着时间的推移存储了太多重复的字符串查询。 它主要存储来自 .Reload() 函数的那些,因为它没有参数化,它将 ID 硬编码到查询中。 然后还有像“ID”这样的字符串,它被缓存在 2947x 的某个地方。

.Reload() 函数有什么方法可以使其参数化,或者清除所有存储的字符串?

此应用每隔几秒钟刷新一次仓库作业和托盘,以使其与所有机器保持同步,由于 WPF 绑定,我不知道比 .Reload() 更好的方法。

编辑 1

我有一个简单的辅助函数,可以一次重新加载许多实体,甚至是一个扩展。将它作为对象传递并不重要,因为即使是最后一个示例,同样的问题仍然存在。

     public static void ReloadEntities(bool dispatch, params IEnumerable<object>[] entities)
        
            using (var ctx = new eWMSEntities())
            
                if (dispatch)
                
                    Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, (SendOrPostCallback)delegate
                    
                        entities.SelectMany(x => x.Select(s => s)).ToList().ForEach(entity =>
                       
                           ctx.Set(entity.GetType()).Attach(entity);
                           ctx.Entry(entity).Reload();
                           ctx.Entry(entity).State = EntityState.Detached;
                       );
                    , null);
                
                else
                
                    entities.SelectMany(x => x.Select(s => s)).ToList().ForEach(entity =>
                    
                        ctx.Set(entity.GetType()).Attach(entity);
                        ctx.Entry(entity).Reload();
                        ctx.Entry(entity).State = EntityState.Detached;
                    );
                
                ctx.Dispose();
            
        

        public static void ReloadEntity(this object entity, bool dispatch)
        
            using (var ctx = new eWMSEntities())
            
                ctx.Set(entity.GetType()).Attach(entity);
                if (dispatch)
                
                    Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, (SendOrPostCallback)delegate
                    
                        ctx.Entry(entity).Reload();
                    , null);
                
                else
                
                    ctx.Entry(entity).Reload();
                
                ctx.Entry(entity).State = EntityState.Detached;
                ctx.Dispose();
            
        
    while (true && JobLines.Contains(line))
            
                using (var ctx = new eWMSEntities())
                
                    ctx.T_JOB_LINES.attach(line);
                    ctx.entry(line).Reload();
                
await Task.Delay(3000);
            

这是运行 3 天后的快照

【问题讨论】:

这将有助于查看几个典型的代码示例,其中您正在加载视图并执行更新/插入以及您认为是短期上下文的内容。 @StevePy 嗨,我添加了如何重新加载实体的示例代码。在这个特定的程序中,我没有做任何插入或更新。我只是将数据保持在线以显示它。 如果它是一次性的(因为您正在“使用”ctx),为什么必须强制使用 ctx.dispose()?使用结束时应该优雅地处理它。 EF6 不进行批量操作。我认为这就是为什么您在重新加载时会看到很多重复的字符串。你可以试试EF Plus。如果您的任何查询使用 Skip、Take 或 Contains,您应该看到这个 answer。至于连接池,请验证服务器中允许的最大连接数。 @KevinCook 这只是解决问题的绝望尝试。 【参考方案1】:

我不推荐,但如果没有其他解决方案... 也许你可以试试

GC.Collect();

让系统强制收集你记忆中不重要的东西。

【讨论】:

你好,谢谢你的想法,但我已经尝试强制 GC,但它现在运行良好。只是 EF 没有得到清理。 我发现关于干净的空值和重复的东西看起来很相似。也许这会有所帮助...link【参考方案2】:

使用“工作单元”模式 - 它可以解决很多问题。我没有找到 WPF,但找到了 ASP.NET MVC

【讨论】:

感谢您的参考,但它并没有真正的帮助

以上是关于EF 6 连接池和存储的查询字符串 RAM 泄漏的主要内容,如果未能解决你的问题,请参考以下文章

字符串常量池和String::intern()的讨论

字符串常量池和String::intern()的讨论

ASP.NET MVC 4 EF6 无法连接到 SQL Server Express 数据库

数据库连接池和线程池

(每天进步一点点)mybits连接池和tomcat线程配置

Java中的连接池和线程池设置