调查实体框架核心中的内存泄漏

不要让内存泄漏成为洪水

术语“内存泄漏”和“ .NET应用程序”不是经常一起使用。但是,我们最近在一个.NET Core Web应用程序中出现了一系列内存不足异常。事实证明,此问题是由Entity Framework Core中的行为更改引起的,尽管最终的解决方案非常简单,但实现该目标的过程既充满挑战又有趣。

该系统本身托管在Azure中,由Angular SPA前端和后端的.NET Core API组成,使用Entity Framework Core与Azure SQL数据库进行通信。作为专门从事.NET开发的软件咨询公司,我们之前已经编写了许多类似的应用程序。因此,内存不足崩溃[1]是无法预料的,因此我们立即知道这是需要认真对待的事情。使用Azure门户中的指标,我们可以看到内存使用率稳步上升,然后突然下降:此下降是应用程序崩溃。

修复之前 

因此,我们花了一些时间进行调查并逐步进行更改,以解决看似经典的内存泄漏问题。.NET泄漏的常见原因是未正确处理某些问题,在我们的案例中很可能是EF Core数据库上下文。因此,我们遍历了源代码,以寻找可能无法处理上下文的潜在原因。这变成了空白。

我们将Entity Framework Core升级到了最新版本,因为最近的更新包括各种内存泄漏的修复程序和总体效率的提高。

我们还在使用的Application Insights版本中发现了可能的内存泄漏(请参阅https://github.com/microsoft/ApplicationInsights-dotnet/issues/594),因此我们也对该软件包进行了升级。

这些都不能解决问题,因此我们解剖了从Azure应用服务中获取的内存转储(请参阅https://blogs.msdn.microsoft.com/jpsanders/2017/02/02/how-to-get-a-full-memory-dump-in-azure-app-services/)。

我们注意到,绝大多数托管内存最终都由MemoryCache类使用。进一步深入研究表明,大多数缓存数据都是原始SQL查询的形式。我们看到大量的根本上是同一查询的事件被多次缓存,并且参数本身被硬编码在查询中而不是被参数化。

例如,与其像这样缓存查询:

SELECT TOP (1) UserId, FirstName, LastName, EmailAddress
FROM Users
WHERE UserId = @param_1

我们发现这样的多个查询:

SELECT TOP (1) UserId, FirstName, LastName, EmailAddress
FROM Users
WHERE UserId = 5

因此,我们进行了一些搜索,寻找可能与之相关的EF核心问题,并遇到了这个问题:https[2] : //github.com/aspnet/EntityFrameworkCore/issues/10535[3]

关于这个问题的主题指出了这个问题:我们正在建立一个动态表达式树,并使用它Expressions.Expression.Constant 来为where子句提供参数。使用常量表达式意味着Entity Framework Core不会参数化SQL查询,并且是Entity Framework 6的行为更改。

我们到处都使用这个表达式树,通过它的ID来获取某些东西,这就是为什么它是一个很大的问题。

因此,这就是我们所做的更改:

// Before
var param = Expressions.Expression.Parameter(typeof(T));
Expression = Expressions.Expression.Lambda<Func<T, bool>>(Expressions.Expression.Call(Expressions.Expression.Constant(valuesToFilter),"Contains",Type.EmptyTypes,Expressions.Expression.Property(param, propertyName)),param);
// After
var param = Expressions.Expression.Parameter(typeof(T));
// This is what we added
Expression<Func<List<int>>> valuesToFilterLambda = () => valuesToFilter;
Expression = Expressions.Expression.Lambda<Func<T, bool>>(Expressions.Expression.Call(valuesToFilterLambda.Body,"Contains",Type.EmptyTypes,Expressions.Expression.Property(param, propertyName)),param);

使用lambda表达式获取表达式主体会使Entity Framework Core[4]对SQL查询进行参数化,因此仅缓存它的一个实例。

这是包括修订版本在内的一段时间内的内存使用情况。该版本以红色标记,您可以看到差异很大。稳定的内存使用量从未超过200MB,而不断攀升至超过1GB,然后发生崩溃。

修复后

最初进行调查时,真正的解决方案不是我们要注意的事情,而是通过检查内存转储并遵循证据我们最终到达那里。

从此调查中可以汲取的教训是:

•内存转储不会说谎-如果内存泄漏,请先查看证据。•微软已经开放了EF Core的源代码,所有问题在那里所有人都可以看到,对有需求的开发者来说非常方便。•简单的代码更改(在这种情况下为一行)可能会产生巨大的影响。

References

[1] ,内存不足崩溃: https://dzone.com/articles/what-causes-outofmemoryerror
[2] https: https://github.com/aspnet/EntityFrameworkCore/issues/10535
[3] //github.com/aspnet/EntityFrameworkCore/issues/10535: https://github.com/aspnet/EntityFrameworkCore/issues/10535
[4] Entity Framework Core: https://dzone.com/articles/entity-framework-core-30-and-sql-server-2019-perfo

如何分析EFCore引发的内存泄漏相关推荐

  1. Java中由substring方法引发的内存泄漏

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 在Java中我们无须关心内存的释放,J ...

  2. 单例模式引发的内存泄漏:_资源泄漏:救援的命令模式

    单例模式引发的内存泄漏: 多年来, 使用Plumbr进行性能监控时,我遇到了数百个资源泄漏引起的性能问题. 在这篇文章中,我想描述一种最简单的方法来清理资源并避免该问题. 首先,我以电影播放器​​应用 ...

  3. android 内存分析 郭霖_android 内存泄漏(OOM)问题总结

    对于Java来说,就是new出来的Object 放在Heap上无法被GC回收 Paste_Image.png Context Context Context类本身是一个纯abstract类,它有两个具 ...

  4. PerfView专题 (第十篇):洞察 C# 终结队列引发的内存泄漏

    一:背景 C# 程序内存泄漏的诱发因素有很多,但从顶层原理上来说,就是该销毁的 用户根 对象没有被销毁,从而导致内存中意料之外的对象无限堆积,导致内存暴涨,最终崩溃,这其中的一个用户根就是 终结器队列 ...

  5. 详细分析内部类的发生内存泄漏的原因

    文章目录 避免内部类中的内存泄漏 步骤1:内部类引用其外部类 步骤2:构造函数获取封闭的类引用 步骤3:声明一种新方法 内存泄漏的解剖 避免内部类中的内存泄漏 使用内部类时要当心垃圾收集 如果您已了解 ...

  6. Android内存泄漏定位、分析、解决全方案

    为什么会发生内存泄漏 内存空间使用完毕之后未回收, 会导致内存泄漏.有人会问:Java不是有垃圾自动回收机制么?不幸的是,在Java中仍存在很多容易导致内存泄漏的逻辑(logical leak).虽然 ...

  7. Android内存泄漏的分析和避免

    内存泄漏 Java是垃圾回收语言的一种,其优点是开发者无需特意管理内存分配,降低了应用由于局部故障(segmentation fault)导致崩溃,同时防止未释放的内存把堆栈(heap)挤爆而导致程序 ...

  8. Android内存泄漏分析及调试

    2019独角兽企业重金招聘Python工程师标准>>> Android内存泄漏分析及调试 分类: Android2013-10-25 11:31 5290人阅读 评论(5) 收藏 举 ...

  9. 设置log缓存_全局变量、事件绑定、缓存爆炸?Node.js内存泄漏问题分析

    作者:elvinpeng,腾讯 WXG 前端开发工程师 Node.js 使用的是 V8 引擎,会自动进行垃圾回收(Garbage Collection,GC),因而写代码的时候不需要像 C/C++ 一 ...

最新文章

  1. FreeRtos 内核函数 cmsis_os函数一览
  2. 毕业设计——学术交流管理系统的设计与实现-1
  3. 我都不敢信了 东芝芯片“又”将最后决定
  4. mysql的concat函数_MySQL中concat函数(连接字符串)
  5. 提高篇 第五部分 动态规划 第4章 状态压缩类动态规划
  6. 拳王虚拟项目公社:通过网络卖虚拟产品,月入1W的全自动化推广引流技术
  7. mysql表空间增长过快_Oracle表空间增长异常解决又一例
  8. PHP设计模式——备忘录模式
  9. Java:Spring @Transactional工作原理
  10. 跨域技术-jsonp
  11. 【已解决】FAILURE: Build failed with an exception......
  12. 球体重量在线计算机,材料重量计算器
  13. EBT 道客巴巴的加密与破解 序章
  14. html制作图片幻灯片效果代码,【JS+CSS3】实现带预览图幻灯片效果的示例代码
  15. PDF文件旋转页面的简单方法
  16. 智能手机扬声器、听筒及耳机阻抗及音频效果比较
  17. 过来人教你如何系统学STM32
  18. pandas学习笔记之DateFrame
  19. 【重庆SEO教程】如何诊断一个网站SEO优化的好坏
  20. EMC-浪涌防护及退耦设计

热门文章

  1. allegro下快捷键设置[转贴]
  2. 存储过程学习笔记(一)
  3. 初学ASP.NET 必看
  4. linux df命令功能,Linux df命令简要介绍
  5. Mac OS X必备APP推荐之二
  6. linux下设备或资源忙,linux删除文件目录 目录设备或资源忙怎么办
  7. python实现异步的几种方式_终于搞明白了,异步Python比同步Python究竟快在哪里?...
  8. 深入剖析Redis系列(五) - Redis数据结构之字符串
  9. 中兴智能视觉大数据:人脸识别技术目前处于“用的不够,用的不好”
  10. 8-12 canvas专题-阶段练习一(上)