我将2个非常大的数据集放入内存,执行连接以从第一个集合中过滤掉一个子集,然后尝试销毁第二个集合,因为它使用了大约600MB的系统RAM。问题是下面的代码不起作用。在下面的代码运行后,foreach循环运行大约需要15分钟。在此期间,内存不会从600MB +减少。我做错了吗?
List<APPLES> tmpApples = dataContext.Apples.ToList(); // 100MB
List<ORANGES> tmpOranges = dataContext.Oranges.ToList(); // 600MB
List<APPLES> filteredApples = tmpApples
.Join(tmpOranges, apples => apples.Id, oranges => oranges.Id, (apples, oranges) => apples).ToList();
tmpOranges.Clear();
tmpOranges = null;
GC.Collect();
注意我稍后重新使用tmpApples,所以我现在不清除它..
答案 0 :(得分:5)
清除,取消和收集几乎没有任何(积极的)效果。 GC将自动检测何时不再引用对象。此外,只要Join
操作运行,tmpApples
和tmpOranges
集合都会被引用,并且所有对象都会被引用。因此无法收集它们。
更好的解决方案是在数据库中进行过滤:
// NOTE That I removed the ToList operations
IQueryable<APPLE> tmpApples = dataContext.Apples;
IQueryable<ORANGE> tmpOranges = dataContext.Oranges;
List<APPLES> filteredApples = tmpApples
.Join(tmpOranges, apples => apples.Id,
oranges => oranges.Id, (apples, oranges) => apples)
.ToList();
答案 1 :(得分:5)
有几点需要注意:
dataContext
可以清除/垃圾收集,否则很可能会保留对很多对象的引用Clear()
然后将变量设置为null是没有意义的,如果你真的没有对列表做任何其他事情。几乎在所有情况下,GC都可以告诉您何时不再使用变量。答案 2 :(得分:1)
未收回此数据的原因是因为虽然您正在清除集合(因此集合不再引用项目), DataContext
会保留引用,这会导致它保持不变存储器强>
您必须在完成后立即处置DataContext
。
好的,你可能已成为large object issue的牺牲品。
答案 3 :(得分:1)
假设这是一个大对象堆问题,您可能会尝试不立即检索所有苹果,而是将它们放入“数据包”中。所以不要打电话
List<APPLE> apples = dataContext.Apples.ToList()
而是尝试将苹果存储在单独的列表中
int packetSize = 100;
List<APPLE> applePacket1 = dataContext.Apples.Take(packetSize);
List<APPLE> applePacket2 = dataContext.Applies.Skip(packetSize).Take(packetSize);
这有帮助吗?
答案 4 :(得分:0)
使用一些分析工具或SOS.dll来查找您的内存所属的位置。如果某些操作需要花费很多时间,这听起来就像是在交换页面文件。
编辑:还要记住,Debug版本将延迟收集不再引用的局部变量,以便于调查。
答案 5 :(得分:-1)
你唯一错误的是显式调用垃圾收集器。你不需要这样做(事实上你不应该这样做)而且史蒂文说你不需要对收藏品做任何事情,他们最终会离开 - 最终。
如果你担心的是15分钟foreach循环的表现,那么你应该发布这个循环。它可能与内存使用无关。