我在循环中下载了大量数据但是在一些操作之后我删除它们但我看到的是内存分配正在快速增长,几秒钟和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();
}
}
答案 0 :(得分:12)
您可以做的第一件事是禁用更改跟踪,因为您没有更改代码中的任何数据。这可以防止加载的对象附加到上下文:
对于DbContext
(EF> = 4.1):
var inputs = contex.AIMRInputs.AsNoTracking()
.Where(x => x.Input_Type == 1);
和
var data = contex.Values.AsNoTracking()
.Where(x => x.InputID == input.InputID)
.OrderBy(x => x.TimeStamp)
.ToList();
修改强>
对于EF 4.0,您可以按原样保留查询,但将以下内容添加为using
块中的前两行:
contex.AIMRInputs.MergeOption = MergeOption.NoTracking;
contex.Values.MergeOption = MergeOption.NoTracking;
这会禁用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();
假设所有3个已加载的订单都分配了相同的客户。因为我们没有禁用跟踪EF将实现:
总和:100字节
(为简单起见,我假设具有复制属性值的上下文条目与实体本身具有相同的大小。)
现在我们使用禁用的更改跟踪运行查询:
var orderList = context.Orders.AsNoTracking()
.Include(o => o.Customer).Take(3).ToList();
具体化数据为:
总和:90字节
因此,在这种情况下,使用AsNoTracking
查询会减少10个字节的内存。
现在,使用5个订单(Take(5)
)进行相同的计算,同样所有订单都拥有相同的客户:
没有AsNoTracking
:
总和:140字节
使用AsNoTracking
:
总和:150字节
这次使用AsNoTracking
要贵10个字节。
上面的数字非常粗糙,但某处是一个收支平衡点,使用AsNoTracking
可能需要更多内存。
使用AsNoTracking
与否之间的内存消耗差异很大程度上取决于查询,模型中的关系以及查询加载的具体数据。例如:当上述示例中的订单(或大部分)具有不同的客户时,AsNoTracking
在内存消耗方面总是更好。
结论:AsNoTracking
主要用作提高查询性能的工具,而非内存使用。在许多情况下,它也会消耗更少的内存。但如果特定查询需要更多内存AsNoTracking
,请不要感到惊讶。最后,您必须衡量内存占用量,以便做出有利于或反对AsNoTracking
的明确决策。
答案 1 :(得分:1)
如果此处的问题可能与DataContext有关。其中许多缓存信息或在执行查询时存储其他信息,因此内存占用将随着时间的推移而增长。我会首先检查一个分析器,但如果这是你的问题,你可能需要在每次X请求后重新创建一个新的datacontext(尝试使用不同的X值来看看哪种方法效果最好)。
我还想指出,大多数人往往有很多记忆。在开始进行这些类型的优化之前,您应该确定使用的内存比真正可接受的内存多。由于可用内存较少,GC还将开始更积极地清除内存。它不会过早地优化(也不应该)。