递归导致内存不足

时间:2009-03-16 07:07:46

标签: memory recursion

我有2 GB的RAM。我们有一个执行导出/导入操作的应用程序。 我们有一个递归函数,它有一个类型为Set的局部变量,它会在每次迭代时继续填充。这个集合不断增长,一度我们的内存不足。

是否有可以最佳使用内存的替代数据结构?

这是粗略的代码

GetObjectsForExportImpl(long lExportOptions, __int64 numIdProject, XExportSets
     &exportSets, long lClientId, CComPtr<IEPIPDServer> ptrIPDServer,FILE *fp)
{
    XExportSets exportLocal;   //Thats a structure containing the Set
    QueryObjectsForExport(lExportOptions, numIdProject, exportLocal,
         lClientId, ptrIPDServer);
    SetIDs::iterator it = exportLocal.setShared.begin();

    for (; it != exportLocal.setShared.end(); ++it)
    {
         //recursive call
         pExportObject->GetObjectsForExportImpl(lExportOptions,
             numIdProject, exportSets, lClientId, ptrIPDServer,fp);
    }
}

6 个答案:

答案 0 :(得分:7)

另一种结构无济于事。假设您切换到使用一半内存的类。你仍然只是拖延了厄运。

结构大小为2GB通常表示您需要切换到基于磁盘的结构,数据库或内存映射的哈希表。

答案 1 :(得分:1)

按件而不是一次处理数据。

那是:

while (not end-of-file) {
   data = read_some_information();
   export_some_information(data);
}

除非您处于一个非常特殊的情况,您需要所有数据才能进行导出(这种情况极不可能)

答案 2 :(得分:1)

暂时,比较您原来的方法调用:

GetObjectsForExportImpl(
   long                  lExportOptions, 
   __int64               numIdProject, 
   XExportSets           &exportSets, 
   long                  lClientId, 
   CComPtr<IEPIPDServer> ptrIPDServer,
   FILE                  *fp
   )

到你后来的递归电话:

hr = pExportObject->GetObjectsForExportImpl(
                         lExportOptions,
                         numIdProject,
                         exportSets,
                         lClientId,
                         ptrIPDServer,
                         fp);

除非在这些之间发生魔法,否则您只需使用自己的参数集重新调用该方法。我怀疑你打算在那里输入'exportLocal'而不是'exportSets',因为否则,exportLocal.setShared.begin()有什么意义呢?您将继续重新创建一个新的exportLocal,告诉它开始,递归等等。

简而言之,我认为问题是编码错误,而不是递归问题。

作为旁注 - 你能想到一种方法使它成为循环,而不是递归吗?循环几乎总是更快,更简单,更容易理解和快速调试。

答案 3 :(得分:1)

抱歉 - 我真的不懂C ++,但我可能会有所帮助。如果您可以使用下标符号来访问元素,并且您有指向父元素的指针,则可以使用堆栈进行深度优先遍历,并避免递归的不可忽略的成本。以下是您应该能够翻译的一些C#代码:

Stack<int> childIndex = new Stack<int>();
childIndex.Push(0);

TreeNode<Folder> workingFolder = GetNodeById(folderId);
TreeNode<Folder> returnFolder = ShallowClone(workingFolder);

while (childIndex.Count > 0) {
    int idx = childIndex.Peek();
    if (idx < workingFolder.Children.Count) {
        visit(workingFolder.Children[idx]);

        // increment count for this level
        childIndex.Pop();
        childIndex.Push(idx + 1);

        // replace current working folders and push new index
        workingFolder = workingFolder.Children[idx];
        returnFolder = f;
        childIndex.Push(0);
    } else {
        // no (more) children
        workingFolder = (workingFolder.Parent == null ? workingFolder : workingFolder.Parent);
        returnFolder = (returnFolder.Parent == null ? returnFolder : returnFolder.Parent);
        childIndex.Pop();
    }
}

答案 4 :(得分:0)

如果您的递归占用了2GB的内存,那么您可能会遇到任何类型的内存数据结构问题。您可以发布一些代码,以便我们更好地了解您正在做什么吗?

一个想法可能是使用数据库表来存储Set,因为您正在构建它。您可以为每个递归插入一个新记录,该记录可以具有对表中父记录的FK引用。这样,您可以通过跟踪记录中的父引用来上下移动递归。

答案 5 :(得分:0)

我不认为递归与您的问题有很大关系。问题仅在于您创建的数据很大。转向迭代解决方案无济于事。正如已经指出的那样,在遍历时写输出,而不是将其存储在内存结构中。

但是,您可以通过在递归调用中传递指针而不是整个结构来最小化堆栈上的内容。