如何分析EFCore引发的内存泄漏

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

不要让内存泄漏成为洪水

术语“内存泄漏”和“ .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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310392.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构与算法-- 二叉树中和为某一值的路径

二叉树中和为某一值的路径 题目&#xff1a;输入一颗二叉树和一个整数&#xff0c;打印出二叉树中节点值的和为给定值的所有路径。从树的根节点开始往下一只到叶子节点所经过的节点形成一条路径。我们用二叉树节点的定义沿用之前文章中 二叉查找树实现原理定义。如下&#xff…

微服务统计,分析,图表,监控, 分布式追踪一体化的 HttpReports 在 .Net Core 的应用...

前言介绍HttpReports 是针对.Net Core 开发的轻量级APM系统&#xff0c;基于MIT开源协议, 使用HttpReports可以快速搭建.Net Core环境下统计,分析,图表,监控&#xff0c;分布式追踪一体化的站点&#xff0c; 适应.Net Core WebAPI,MVC&#xff0c;Web项目, 通过引用Nuget构建Da…

WPF 创建自定义面板

前面两个章节分别介绍了两个自定义控件:自定义的ColorPicker和FlipPanel控件。接下来介绍派生自定义面板以及构建自定义绘图控件。创建自定义面板是一种特殊但较常见的自定义控件开发子集。前面以及介绍过有关面板方面的知识&#xff0c;了解到面板驻留一个或多个子元素&#x…

vue.js中mock本地json数据

vue.js中mock本地json数据 新版本的vue项目中已经将dev-server.js&#xff0c;dev-client.js两个js文件合并到了webpack.dev.conf.js文件中&#xff0c;以下分别是新旧版本的build目录结构&#xff1a; 新版本&#xff1a; 旧版本&#xff1a; 本次验证mock&#xff1a;运…

互联网40岁失业是一个无法打破的魔咒吗?

最近刚刚过完生日&#xff0c;又大了一岁&#xff0c;距离40岁又进了一步。年纪大了&#xff0c;就要多复盘。最近几天思考的比较多&#xff0c;因为身边失业的朋友开始多了起来。我又有点陷入担忧、焦虑的心态了。好在我一直是个有阿Q精神的中年油腻男&#xff0c;很快安抚好自…

数据结构与算法--复杂链表的复制

复杂链表的复制 题目&#xff1a;实现一个函数complexListNode 复制一个复杂链表。在链表中&#xff0c;每个节点除了有一个next指针指向下一个节点&#xff0c;还有另外一个before节点&#xff0c;before节点指向链表中任意一个节点&#xff0c;或者null节点。链表节点定义使…

如何实时主动监控你的网站接口是否挂掉并及时报警

“ 阅读本文大概需要 10 分钟。 ”最近我在公司负责的业务已经正式投入上线了&#xff0c;既然是线上环境&#xff0c;那么就需要保证其可用性。我负责的业务其中就包括一个 Web Service&#xff0c;我需要保证 Service 的每个接口都是可用的&#xff0c;如果某个时间流量大了或…

数据结构与算法--二叉查找树转顺序排列双向链表

二叉查找树转顺序排列双向链表 题目&#xff1a;输入一颗二叉查找树&#xff0c;将二叉查找树转成一个排序的双向链表&#xff0c;要求不能创建任何新节点&#xff0c;只调整树节点中指针的指向。例如下图所示&#xff1a; 本次二叉查找树节点定义使用之前文章 数据结构与算法…

5种避免C#.NET中因事件造成内存泄漏的技术

原文来自互联网&#xff0c;由长沙DotNET技术社区编译。 5种避免C&#xff03;.NET中事件造成的内存泄漏的技术C&#xff03;&#xff08;通常是.NET&#xff09;中的事件注册是内存泄漏的最常见原因。至少从我的经验来看。实际上&#xff0c;我从事件中看到了太多的内存泄漏&a…

数据结构与算法--字符串的排列组合问题

字符串的全排列 题目&#xff1a;输入一个字符串&#xff0c;打印出改字符串中所有字符的所有排列。例如输入字符串abc&#xff0c;那么打印出由a&#xff0c;b&#xff0c;c字符组成的所有字符串&#xff1a;abc&#xff0c;acb&#xff0c;bac&#xff0c;bca&#xff0c;cab…

[GitHub] 75+的 C# 数据结构和算法实现

C#中标准数据结构和算法的即插即用类库项目GitHub&#xff1a;https://github.com/aalhour/C-Sharp-AlgorithmsWatch: 307 Star: 3.4k Fork: 910o---o | |/ --O---O--O | |\ --O---O--o---o | |O o o--o o--o o---o o-O-o …

我是如何一步步的在并行编程中将lock锁次数降到最低实现无锁编程

在并行编程中&#xff0c;经常会遇到多线程间操作共享集合的问题&#xff0c;很多时候大家都很难逃避这个问题做到一种无锁编程状态&#xff0c;你也知道一旦给共享集合套上lock之后&#xff0c;并发和伸缩能力往往会造成很大影响&#xff0c;这篇就来谈谈如何尽可能的减少lock…

常用Arthas命令

jad反编译 检查线上代码是否修改成功&#xff0c;例如修改interface后看Jar包是否引入新的&#xff0c;或者代码是否最新的。 jad com.zhenai.counseling.business.provider.facade.supremecourse.RedeemRecordFacadeImpl //反编译只展示源码 jad --source-only com.zhenai.c…