2010-11-04 71 views
0

我有以下循环表的方法,改变每一行中的一些值并将chages保存回数据库。为了让事情变得更快,我正在以10,000行的集合来获取数据。这是一张超过2500万条记录的大型表格。如何取消分配内存?

问题是我的应用程序似乎没有释放任何内存。我尝试重新声明records变量为nothing或显式调用垃圾回收器,但内存停留在那里。 运行内置的VS10探查器我可以看到罪魁祸首是system.linq.enumerable.tolist()方法占用了我98%的内存。如何在拨打saveChanges后释放该内存?

db = New databaseEntities 
Dim size = 25000000 
Dim stepSize = 10000 
For i = 0 to size Step stepSize 
    Dim sql = (From A In db.table).OrderBy(Function(A) A.Column).Skip(i).Take(stepSize) 
    Dim records As New List(Of table) 
    records = sql.ToList 
    For Each record In records 
    'do some work 
    Next 
    db.SaveChanges() 
    records = Nothing 
    GC.Collect() 
Next 

回答

0

存储库拥有对其正在跟踪的每个实体的引用,因此在存储库处于活动状态并且跟踪它时,您将无法处置实体。这意味着您需要处理存储库,或者在完成处理后将每个实体分离。选项1)如果“做某些工作”不会影响您将记录返回的顺序,那么可以将ForEase循环中的databaseEntities创建,并用using块声明它。如果你的操作本质上是并行的,而你对一个“表”实体做的任何操作都没有任何依赖关系,那么这个操作应该会导致每一个实体块在for循环中每次释放时都会被释放掉

选项2)那么你可以在db.SaveChanges之后调用databaseEntities.Detach(record),这将使垃圾回收器能够回收实体的空间。

看你的代码,我怀疑任何thse的可用于

+0

选项2非常慢。花费大约一分钟来分离10,000条记录(相比之下,更新大约需要2秒钟)。所以我想我会选择1. – Pavel 2010-11-04 12:04:14

0

也许你可以试试这个:(我没有测试)

db.SaveChanges() 
For Each record In records 
    record.dispose ''only if class table got a dispose method 
Next 
records.clear 
records = Nothing 
+0

不,表格对象中没有配置属性。 – Pavel 2010-11-04 11:27:50

+0

@Pavel ok,也许你可以尝试清晰的方法? – Fredou 2010-11-04 11:30:11

0

我绝不是一个LINQ到SQL专家,但我的猜测是,DataContext的缓存中的所有行你已阅读,因此您必须清空缓存或丢失对DataContext的引用。

+0

我想你在这里有东西。如果我在'for'循环中声明一个新的实例,内存问题就会消失。不过,我认为这不是一个很好的解决方案。应该有一些方法告诉实体管理器清除缓存。 – Pavel 2010-11-04 11:52:01

+0

这不是关于内存管理器,而是关于DataContext。你必须告诉DataContext清除它的缓存,并且内存管理器会在需要时收回内存。 – erikkallen 2010-11-04 12:45:43

+0

@Pavel,对大量记录采取行动是EF的一个弱点。如果我在大量实体中执行相同的操作,并且性能是优先事项,那么我可能会使用存储过程。这确实意味着你的一些业务逻辑现在在数据库中而不是在模型中,但有时我们必须对这些事情保持务实。 – 2010-11-04 14:53:24

0

如果您不需要更新实体,使用MergeOption.NoTracking。上下文将不再保留对实体的引用,也不会修正。

+0

真的,虽然他加载表实体(显然没有别的)的事实,但有一些工作,然后调用db.SaveChanges往往意味着他确实需要跟踪更改。 – 2010-11-04 14:49:32