【问题标题】:run into OutOfMemoryException after dbQuery在 dbQuery 之后遇到 OutOfMemoryException
【发布时间】:2014-10-29 12:16:24
【问题描述】:

我正在运行一个 DB 查询,它返回大量特征(大约 100000 个)。因为我遇到了上述异常,所以我尝试将查询拆分为几个子查询。但是因此所有这些子查询的结果都被写入了方法列表,因此我仍然遇到了同样的异常。

所以我想知道是否可以在每个子查询通过循环其元素并返回每一个元素完成后使用yield return

在检索到这些特性之后,我必须为它们中的每一个创建一些新的自定义对象,所以我想知道在这种情况下使用 yield return 是否会节省内存。

也许下面的内容会更清楚一点:

foreach (var chunk in IDs.chunk(500))
{       
    List<ComplexObject> result = new List<ComplexObject>():

    // ...
    // make a (sub-)query on every chunk to retrieve 500 objects at once
    // ..

    // now we have up to 500 ComplexObjects within result
    foreach (var parcel in result)
    {
        yield return parcel;
        parcel.Release();       // release COM-object
    }
}

其中chunk 是 500 个元素 (ID) 的(子)集合。

之后,我在foreach 中循环从该方法检索到的结果,并从中创建自定义对象。

编辑:我还可以逐个查询和处理每个ComplexObject,实际上这比检索一堆比如说 500 个元素要慢得多,因为 MetaData 只需检索一次,而不是为每个单个对象检索(还有更多原因,但这个最方便)。

【问题讨论】:

  • 这些是 COM 对象,但数据是从数据库中检索的?这个方法的调用者是否需要一次拥有所有这些,或者调用者可以一个一个地处理项目?为什么要“一次”检索 500 个对象?
  • 是的,调用者可能会一个一个地使用它们,而不是一次性使用它们。在进行查询时,我有一个接受 ID 集合并在数组中检索其所有对应的ComplexObjects 的方法,所以实际上result 将是一个数组而不是一个列表,但我想这没什么区别.
  • 但是db查询部分长什么样子呢?那是需要更改的实际位置(该方法的结果需要是IEnumerable&lt;ComplexObject&gt;)。
  • 实际查询在黑盒中(至少对我而言)并且确实返回了一个数组。但是因此 500 个元素是一个小集合,我想一次收集 500 个元素(使用提到的查询),然后循环每个元素并直接将其发送给调用者,而不是等到所有块都处理完毕。
  • “小型收藏”是一个相对术语。如果这些对象中的每一个都消耗 2MB 的内存,那么您说的是 1GB 的 RAM。 “黑匣子(至少对我而言)”是什么意思?您是否有可以修改的代码?您可以将块大小设置为1吗?因为这会有效地将其转化为每个实例的“创建过程释放”操作。

标签: c# out-of-memory yield-return


【解决方案1】:

您应该避免将结果完全存储在列表中。主要思想是实例化每个昂贵的对象,对其进行处理,然后立即处理它。

这意味着你的外部方法看起来像:

foreach (var chunk in IDs.SplitIntoChunks(size: 500))
{
    foreach (var parcel in EnumerateComplexObjects(chunk))
    {
        yield return parcel;
    }
}

EnumerableComplexObjects 也将使用yield return

IEnumerable<ComplexObject> EnumerateObjects(IEnumerable<int> ids)
{
    foreach (var id in ids)
    {
        using (var obj = CreateSingleComplexObject(id))
        {
            yield return obj;
        }
    }
}

注意,一旦你这样做了,你甚至不再需要块了:

foreach (var obj in EnumerateObjects(allIDs)
{
     Process(obj);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 2012-12-01
    • 1970-01-01
    相关资源
    最近更新 更多