kos*_*kov 4 c# memory-leaks entity-framework
我在循环中下载了大量数据但是在一些操作之后我删除了它们但是我看到内存分配正在快速增长,几秒钟和1GB,所以如何在每次迭代后清理?
using (var contex = new DB)
{
var inputs = contex.AIMRInputs.Where(x => x.Input_Type == 1);
foreach (var input in inputs)
{
var data = contex.Values.Where(x => x.InputID == input.InputID).OrderBy(x => x.TimeStamp).ToList();
if (data.Count == 0) continue;
foreach (var value in data)
{
Console.WriteLine(Value.property);
}
data.Clear();
}
}
Run Code Online (Sandbox Code Playgroud)
Sla*_*uma 12
您可以做的第一件事是禁用更改跟踪,因为您没有更改代码中的任何数据.这可以防止加载的对象附加到上下文:
对于DbContext
(EF> = 4.1):
var inputs = contex.AIMRInputs.AsNoTracking()
.Where(x => x.Input_Type == 1);
Run Code Online (Sandbox Code Playgroud)
和:
var data = contex.Values.AsNoTracking()
.Where(x => x.InputID == input.InputID)
.OrderBy(x => x.TimeStamp)
.ToList();
Run Code Online (Sandbox Code Playgroud)
编辑
对于EF 4.0,您可以按原样保留查询,但将以下内容添加为using
块中的前两行:
contex.AIMRInputs.MergeOption = MergeOption.NoTracking;
contex.Values.MergeOption = MergeOption.NoTracking;
Run Code Online (Sandbox Code Playgroud)
这会禁用更改跟踪ObjectContext
.
编辑2
...特别是参考@James Reategui的评论,以AsNoTracking
减少内存占用:
这通常是正确的(就像在这个问题的模型/查询中)但并非总是如此!实际使用AsNoTracking
可能会对内存使用产生反作用.
AsNoTracking
当对象在内存中实现时会怎么做?
第一:它不会将实体附加到上下文,因此不会在上下文的状态管理器中创建条目.这些条目消耗内存.使用POCO时,条目包含实体首次加载/附加到上下文时的属性值的快照 - 基本上是除了对象本身之外的所有(标量)属性的副本.因此,当AsNoTracking
没有应用时,comsumed内存大约是对象大小的两倍.
第二:另一方面,当实体没有附加到上下文时,EF无法利用键值和对象引用标识之间的标识映射的优势.这意味着具有相同键的对象将被多次实现,这将增加内存,而不使用AsNoTracking
EF将确保实体仅在每个键值实现一次.
加载相关实体时,第二点变得尤为重要.简单的例子:
比如,我们有Order
一个Customer
实体,一个订单有一个客户Order.Customer
.假设Order
对象的大小为10字节,Customer
对象的大小为20字节.现在我们运行此查询:
var orderList = context.Orders
.Include(o => o.Customer).Take(3).ToList();
Run Code Online (Sandbox Code Playgroud)
并假设所有3个装载的订单都分配了相同的客户.因为我们没有禁用跟踪EF将实现:
总和:100字节
(为简单起见,我假设具有复制属性值的上下文条目与实体本身具有相同的大小.)
现在我们使用禁用的更改跟踪运行查询:
var orderList = context.Orders.AsNoTracking()
.Include(o => o.Customer).Take(3).ToList();
Run Code Online (Sandbox Code Playgroud)
物化数据是:
总和:90字节
因此,AsNoTracking
在这种情况下,使用查询消耗的内存减少了10个字节.
现在,使用5个订单(Take(5)
)进行相同的计算,所有订单都具有相同的客户:
没有AsNoTracking
:
总和:140字节
用AsNoTracking
:
总和:150字节
这次使用的AsNoTracking
是10字节更贵.
上面的数字是非常粗糙的,但某处是一个收支平衡点,使用AsNoTracking
可能需要更多的内存.
使用AsNoTracking
与否之间的内存消耗差异很大程度上取决于查询,模型中的关系以及查询加载的具体数据.例如:AsNoTracking
当上述示例中的订单(或大部分)具有不同的客户时,内存消耗总是更好.
结论:AsNoTracking
主要用作提高查询性能而非内存使用的工具.在许多情况下,它也会消耗更少的内存.但如果特定查询需要更多内存,请不要感到惊讶AsNoTracking
.最后,您必须衡量内存占用,以便做出有利于或反对的可靠决策AsNoTracking
.