Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用C/ADO.Net实体复制大型数据库时内存不足_C#_Ado.net_Garbage Collection - Fatal编程技术网

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

C# 使用C/ADO.Net实体复制大型数据库时内存不足,c#,ado.net,garbage-collection,C#,Ado.net,Garbage Collection,还有一个如何释放内存的问题: 我正在两个数据库之间复制数据,这两个数据库当前相同,但很快就会失去同步。我使用反射和ADO.Net实体在C中构建了一个框架应用程序,它可以实现以下功能: 对于源数据库中的每个表: 清除目标数据库中的相应表 对于源表中的每个对象 对于源对象中的每个属性 如果目标对象中存在同名属性,请使用反射将源属性复制到目标属性 这非常有效,直到我找到一个900MB的大表,其中有用户上传的文件 将每个BLOB复制到我的计算机并返回到目标数据库的过程会占用本地内存,每个BLOB的最大容

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

我正在两个数据库之间复制数据,这两个数据库当前相同,但很快就会失去同步。我使用反射和ADO.Net实体在C中构建了一个框架应用程序,它可以实现以下功能:

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

清除目标数据库中的相应表 对于源表中的每个对象 对于源对象中的每个属性 如果目标对象中存在同名属性,请使用反射将源属性复制到目标属性 这非常有效,直到我找到一个900MB的大表,其中有用户上传的文件

将每个BLOB复制到我的计算机并返回到目标数据库的过程会占用本地内存,每个BLOB的最大容量为7 MB。然而,内存并没有得到释放,一旦复制了大约750MB的数据,进程就会死掉——当抛出OutOfMemoryException时,我的程序有1500MB的分配空间,大概是迄今为止复制的所有内容的两个副本

我先尝试了一种天真的方法,做了一个简单的复制。它在每一张桌子上都起作用,直到我找到那张大桌子。我已经尝试强制使用GC.Collect,但结果没有明显变化。我还尝试将实际副本放入一个单独的函数中,希望引用超出范围将有助于它获得GCed。我甚至放了一个线程。睡懒觉,让后台进程有更多的时间运行。所有这些都没有效果

以下是目前存在的相关代码:

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是一个传入的布尔变量,表示应该进行额外的处理,它仅在大表上为true,否则为false


因此,我的问题是:如何修改此代码以避免内存不足?

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


这意味着您的上下文定义的范围太高。根据您的编辑,您似乎正在跨表使用它。那…不好。您尚未显示它的定义位置,但无论它位于何处,它都应该位于较低的级别。请记住,因为连接池创建新上下文并不昂贵,而且根据您的用例,您不需要依赖大量缓存信息,因为您不会多次接触项目,所以创建新上下文不会增加性能成本,即使它大大减少了内存占用。

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


这意味着您的上下文定义的范围太高。根据您的编辑,您似乎正在跨表使用它。那…不好。您尚未显示它的定义位置,但无论它位于何处,它都应该位于较低的级别。请记住,因为连接池创建新上下文并不昂贵,而且根据您的用例,您不需要依赖大量缓存信息,因为您不会多次接触项目,所以创建新上下文不会增加性能成本,即使这大大减少了您的内存占用。

您如何声明/使用Source和Dest?根据提供的代码,我看不到任何东西,但我也认为您需要包含其他代码。@Jared:我添加的函数declarationEF并不是专门为批量操作设计的,类似的操作应该直接在数据库上完成,而不是通过客户端应用程序和EF,我想…关于我自己的问题的最后一点意见是:我无法创建一个干净的泛型来创建上下文并进行低内存复制,因此复制这一个表的过程没有使用泛型。您如何声明/使用Source和Dest?根据提供的代码,我看不到任何东西,但我也认为您需要包含其他代码。@Jared:我添加的函数declarationEF并不是专门为批量操作设计的,类似的操作应该直接在数据库上完成,而不是通过客户端应用程序和EF,我想…关于我自己的问题的最后一点意见是:我无法制作一个干净的泛型来创建上下文并进行低内存复制,所以复制这一个表的过程没有使用泛型。是的,我在两个不同的服务器之间传输数据,我知道EF并不是真正用于这类事情的。但是有了数据转换,我将不得不做一次这个项目
ect已经启动并运行,我会觉得用C比用SQL更舒服,除了这个巨大的表,它是如此小的一个DB,这不是一个问题。这个表有900MB,整个数据库不到1GB。@AricTenEyck我没有说不使用EF或直接使用SQL。我说过在一个较小的范围内声明多个上下文,而不是重用一个上下文。我最后为每个创建的项目创建了一个新的上下文。源上下文仍然非常大,但还不足以让我耗尽内存。如果桌子变大了,我得换一种方式。谢谢你的帮助。是的,我在两个不同的服务器之间传输数据,我知道EF并不是真的用于这种事情。但是一旦这个项目启动并运行,我就必须进行数据转换,我会觉得用C语言比用SQL语言更舒服,而且除了这个巨大的表,它的数据库非常小,所以这不是一个问题。这个表是900MB,整个数据库小于1GB。@AricTenEyck我没有说过不使用EF或直接使用SQL。我说过在一个较小的范围内声明多个上下文,而不是重用一个上下文。我最后为每个创建的项目创建了一个新的上下文。源上下文仍然非常大,但还不足以让我耗尽内存。如果桌子变大了,我得换一种方式。谢谢你的帮助。