gpt4 book ai didi

c# - 使用 C#/ADO.Net 实体复制大型数据库时内存不足

转载 作者:太空宇宙 更新时间:2023-11-03 21:53:41 26 4
gpt4 key购买 nike

又一个如何释放内存的问题:

我正在两个目前相同但很快就会不同步的数据库之间复制数据。我使用 Reflection 和 ADO.Net Entities 在 C# 中组合了一个骨架应用程序来执行此操作:

对于源数据库中的每个表:

  • 清除目标数据库中的对应表
  • 对于源表中的每个对象
    • 对于源对象中的每个属性
      • 如果目标对象中存在同名属性,则使用反射将源属性复制到目标属性

在我到达其中包含用户上传文件的 900MB 大表之前,这非常有用。

将 blob(每个最多 7 MB)复制到我的机器并返回目标数据库的过程耗尽了本地内存。但是,该内存不会被释放,一旦复制了大约 750 MB 的数据,该进程就会终止 - 当抛出 OutOfMemoryException 时,我的程序有 1500 MB 的分配空间,大概是到目前为止复制的所有内容的两个副本。

我先尝试了一种简单的方法,做一个简单的复制。它在每张 table 上都有效,直到我拿到大 table 。我试过强制执行 GC.Collect(),但结果没有明显变化。我还尝试将实际副本放入一个单独的函数中,希望超出范围的引用可以帮助它获得 GC。我什至放了一个 Thread.Sleep 来尝试给后台进程更多的时间来运行。所有这些都没有效果。

这是目前存在的相关代码:

public static void CopyFrom<TSource, TDest>(this ObjectSet<TDest> Dest, ObjectSet<TSource> Source, bool SaveChanges, ObjectContext context)
where TSource : class
where TDest : class {

int total = Source.Count();
int count = 0;
foreach (var src in Source) {
count++;
CopyObject(src, Dest);

if (SaveChanges && context != null) {
context.SaveChanges();
GC.Collect();
if (count % 100 == 0) {
Thread.Sleep(2000);
}
}
}
}

我没有包含 CopyObject() 函数,它只是使用反射来评估 src 的属性并将它们放入新对象中的同名属性中以附加到 Dest。

SaveChanges 是一个 bool 变量,表示应该完成这个额外的处理,它只在大表上为真,否则为假。

那么,我的问题是:如何修改这段代码以免内存不足?

最佳答案

问题是您的数据库上下文在内部使用了大量缓存,它保留了大量信息并阻止垃圾收集器释放它(无论您是否调用 Collect)。

这意味着您的上下文定义范围过大。 (根据您的编辑,您似乎正在跨表使用它。那......不好。)您没有显示它的定义位置,但无论它在哪里,它都应该处于较低级别。请记住,由于创建新上下文的连接池并不昂贵,并且根据您的用例,您不需要如此频繁地依赖大量缓存信息(因为您不会多次触摸项目)新上下文不应增加性能成本,即使它大大减少了内存占用。

关于c# - 使用 C#/ADO.Net 实体复制大型数据库时内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13292464/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com