迁移过程中 Entity Framework 内存不足 - C#
Out of memory with Entity Framework in a migration process- C#
我正在进行迁移过程,必须将所有信息从一个数据库复制到另一个数据库。当它开始 运行 时一切似乎都很好,问题是当进程达到复杂的 table 时。
这个table很特别,因为有一些实体依赖于它。我将用一个例子更好地解释它:
- entityX 是一个人。
- entityX 可以有 entityY(id account)
- entityX 可以有很多 entityZ(朋友)
- entityX 可以有很多 entityV(地址)
- entityX 可以有很多 entityW(cars)
进程插入1159 entityX及其依赖时出现内存不足异常,多则少
在每个 entityX 之后,我们使用一个函数调用 CleanMemory,它使用 GarbageCollector 来清理内存。
这个问题有什么解决办法吗?
public static void LoadExample(origin agmCtx, destinity.AgroPelayoEntities agpCtx)
{//GET ALL THE INFO THAT WE NEED
List<EntityX> listOriginX = agmCtx.EntityX.AsNoTracking().ToList();
foreach (EntityX ent in list)
{
///LISTS INSERTS//////
List<destinityEntityX> listInsert = new List<destinity.EntityX>();
List<destinity.EntityY> listInsertY = new List<destinity.EntityY>();
List<destinity.EntityZ> listInsertZ = new List<destinity.EntityZ>();
List<destinity.EntityV> listInsertV = new List<destinity.EntityV>();
List<destinity.EntityW> listInsertW = new List<destinity.EntityW>();
///LISTS UPDATES//////
List<destinity.EntityX> listUpdate = new List<destinity.EntityX>();
Boolean exists = listOriginX.Any(e => (e.n_id == ent.n_id));
if (!exists)
{
//HERE GOES CODE TO CREATE NEW ENTITY AND HIS CHILD(EntityY,List<listInsertZ>, List<EntityV>....)
listInsertY.Add(newEntityW);
listInsertY.Add(newEntityV);
listInsertY.Add(newEntityZ);
listInsertY.Add(newEntityY);
listInsert.Add(newEntityX);
}
else
{
//MODIFY TO HAVE NEW INFO
listUpdateV.Add(oldEntityV_Modified);
}
int batchSizeX = ClassCommonFuncts.GetNumBatchCount(listInsert.Count());
int batchSizeY= ClassCommonFuncts.GetNumBatchCount(listInsertY.Count());
int batchSizeZ = ClassCommonFuncts.GetNumBatchCount(listInsertZ.Count());
int batchSizeV = ClassCommonFuncts.GetNumBatchCount(listInsertV.Count());
int batchSizeW = ClassCommonFuncts.GetNumBatchCount(listInsertW.Count());
int batchSizeUpdateX = ClassCommonFuncts.GetNumBatchCount(listUpdateV.Count());
agpCtx.BulkInsert<destinity.EntityW>(listInsertW, bulk => bulk.BatchSize = batchSizeW);
agpCtx.BulkInsert<destinity.EntityV>(listInsertV, bulk => bulk.BatchSize = batchSizeV);
agpCtx.BulkInsert<destinity.EntityZ>(listInsertZ, bulk => bulk.BatchSize = batchSizeZ);
agpCtx.BulkInsert<destinity.EntityY>(listInsertY, bulk => bulk.BatchSize = batchSizeY);
agpCtx.BulkInsert<destinity.EntityX>(listInsert, bulk => bulk.BatchSize = batchSizeX);
agpCtx.BulkUpdate<destinity.EntityX>(listUpdate, bulk => bulk.BatchSize = batchSizeUpdateX);
ClassCommonFuncts.CleanMemory();
}
}
函数清理内存
[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);
public static void CleanMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
函数 GetNumBatchCount
public static int GetNumBatchCount(decimal records)
{
if (records > 1000000)
{
return (int)Math.Ceiling((double)records / 1000);
}
else if (records > 500000)
{
return (int)Math.Ceiling((double)records / 100);
}
else if (records > 100000)
{
return (int)Math.Ceiling((double)records / 50);
}
else if (records > 5000)
{
return (int)Math.Ceiling((double)records / 10);
}
else
{
return (int)Math.Ceiling((double)records / 1);
}
}
不是长久之计。首先尝试为您的列表设置容量。
在你调用的地方调用 GC 也是一种不好的做法。
还有一件事。在每次迭代中创建新列表是不好的做法,并且在像这样的代码中内存泄漏是预期的。
最终的解决方案是"simple"。问题是 EntityY 与另一个实体(1 到 n)有关系,然后当应用程序 运行 超过 1000 个 EntityX 崩溃并抛出 OutOfMemory 异常。
我修复了它,将它们分成小组加载,例如按年龄和男性分组。 (就我而言,我做了另一组)
我正在进行迁移过程,必须将所有信息从一个数据库复制到另一个数据库。当它开始 运行 时一切似乎都很好,问题是当进程达到复杂的 table 时。
这个table很特别,因为有一些实体依赖于它。我将用一个例子更好地解释它:
- entityX 是一个人。
- entityX 可以有 entityY(id account)
- entityX 可以有很多 entityZ(朋友)
- entityX 可以有很多 entityV(地址)
- entityX 可以有很多 entityW(cars)
进程插入1159 entityX及其依赖时出现内存不足异常,多则少
在每个 entityX 之后,我们使用一个函数调用 CleanMemory,它使用 GarbageCollector 来清理内存。
这个问题有什么解决办法吗?
public static void LoadExample(origin agmCtx, destinity.AgroPelayoEntities agpCtx)
{//GET ALL THE INFO THAT WE NEED
List<EntityX> listOriginX = agmCtx.EntityX.AsNoTracking().ToList();
foreach (EntityX ent in list)
{
///LISTS INSERTS//////
List<destinityEntityX> listInsert = new List<destinity.EntityX>();
List<destinity.EntityY> listInsertY = new List<destinity.EntityY>();
List<destinity.EntityZ> listInsertZ = new List<destinity.EntityZ>();
List<destinity.EntityV> listInsertV = new List<destinity.EntityV>();
List<destinity.EntityW> listInsertW = new List<destinity.EntityW>();
///LISTS UPDATES//////
List<destinity.EntityX> listUpdate = new List<destinity.EntityX>();
Boolean exists = listOriginX.Any(e => (e.n_id == ent.n_id));
if (!exists)
{
//HERE GOES CODE TO CREATE NEW ENTITY AND HIS CHILD(EntityY,List<listInsertZ>, List<EntityV>....)
listInsertY.Add(newEntityW);
listInsertY.Add(newEntityV);
listInsertY.Add(newEntityZ);
listInsertY.Add(newEntityY);
listInsert.Add(newEntityX);
}
else
{
//MODIFY TO HAVE NEW INFO
listUpdateV.Add(oldEntityV_Modified);
}
int batchSizeX = ClassCommonFuncts.GetNumBatchCount(listInsert.Count());
int batchSizeY= ClassCommonFuncts.GetNumBatchCount(listInsertY.Count());
int batchSizeZ = ClassCommonFuncts.GetNumBatchCount(listInsertZ.Count());
int batchSizeV = ClassCommonFuncts.GetNumBatchCount(listInsertV.Count());
int batchSizeW = ClassCommonFuncts.GetNumBatchCount(listInsertW.Count());
int batchSizeUpdateX = ClassCommonFuncts.GetNumBatchCount(listUpdateV.Count());
agpCtx.BulkInsert<destinity.EntityW>(listInsertW, bulk => bulk.BatchSize = batchSizeW);
agpCtx.BulkInsert<destinity.EntityV>(listInsertV, bulk => bulk.BatchSize = batchSizeV);
agpCtx.BulkInsert<destinity.EntityZ>(listInsertZ, bulk => bulk.BatchSize = batchSizeZ);
agpCtx.BulkInsert<destinity.EntityY>(listInsertY, bulk => bulk.BatchSize = batchSizeY);
agpCtx.BulkInsert<destinity.EntityX>(listInsert, bulk => bulk.BatchSize = batchSizeX);
agpCtx.BulkUpdate<destinity.EntityX>(listUpdate, bulk => bulk.BatchSize = batchSizeUpdateX);
ClassCommonFuncts.CleanMemory();
}
}
函数清理内存
[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);
public static void CleanMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
函数 GetNumBatchCount
public static int GetNumBatchCount(decimal records)
{
if (records > 1000000)
{
return (int)Math.Ceiling((double)records / 1000);
}
else if (records > 500000)
{
return (int)Math.Ceiling((double)records / 100);
}
else if (records > 100000)
{
return (int)Math.Ceiling((double)records / 50);
}
else if (records > 5000)
{
return (int)Math.Ceiling((double)records / 10);
}
else
{
return (int)Math.Ceiling((double)records / 1);
}
}
不是长久之计。首先尝试为您的列表设置容量。
在你调用的地方调用 GC 也是一种不好的做法。
还有一件事。在每次迭代中创建新列表是不好的做法,并且在像这样的代码中内存泄漏是预期的。
最终的解决方案是"simple"。问题是 EntityY 与另一个实体(1 到 n)有关系,然后当应用程序 运行 超过 1000 个 EntityX 崩溃并抛出 OutOfMemory 异常。
我修复了它,将它们分成小组加载,例如按年龄和男性分组。 (就我而言,我做了另一组)