2009-03-16 9 views
4

私は2GBのRAMを持っています。エクスポート/インポート操作を実行するアプリケーションがあります。 私たちには、Set型の1つのローカル変数を持つ再帰関数があります。このセットは成長し続け、ある時点ではメモリが足りなくなります。メモリ不足の再帰

メモリを最適に使用できる代替データ構造はありますか?

は、ここで代替構造はあまり役に立たないラフなコード

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); 
    } 
} 
+0

アルゴリズムについて少し詳しく説明できますか?あなたがセットで何をするのか、アルゴリズムがどのように反復するのかを大まかに説明してください。 – TrayMan

+0

は大まかなコードを編集しました –

答えて

7

です。半分のメモリを使用するクラスに切り替えたとします。それでもあなたは運命を遅らせるだけです。

通常、2GBの構造サイズは、ディスクベースの構造、データベース、またはメモリマップハッシュテーブルに切り替える必要があることを示します。

+0

はい私はディスクベースのアルゴリズムを実装しました。それは私を少し助けてくれました。しかし、ある時点でまだメモリが使い果たされています –

+0

最初にデータがないとメモリが使い果たされるのですか? –

+0

ご迷惑をおかけして申し訳ありません。私はメモリ内の参照のためにいくつかのデータが必要です –

1

データをすべてではなくまとめて扱います。

です:

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

あなたの再帰が食べている場合、あなたはすべてのデータが(非常に低いです)エクスポートを行うことができるようにする必要があり非常に特殊なケース

+0

これは問題です。セット内の要素は相互に依存しているので、それらをクリアすることはできません。 –

+0

依存関係は分離されているか、実際には他の要素に依存している可能性がありますか? – sharptooth

+0

本当に重要なこと:前の要素のすべてのデータが必要なのか、何らかの累積値(合計や平均など)が必要ですか。実際にすべての以前のセットのデータを照会する必要がある場合は、必ずデータベースを記入して照会してエクスポートを作成してください。 –

0

でない限り2GBのメモリを使用すると、おそらくあらゆる種類のメモリ内データ構造に問題が生じるでしょう。あなたが行っていることをより良く理解できるように、コードの一部を投稿できますか?

ビルド中にセットを保存するために、データベーステーブルを使用することが考えられます。それぞれの再帰に対して新しいレコードを挿入することができ、そのレコードはテーブルの親レコードへのFK参照を持つことができます。こうすることで、レコード内の親参照に従うことで再帰を上下に移動することができます。あなたのその後の再帰呼び出しに

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

1

現時点では、あなたのオリジナルのメソッド呼び出しを比較

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

何かの魔法は、それらの間で起こっている場合を除き、あなたは、単にメソッドを再呼び出しされていますそれ自身の議論のセットと一緒に。 exportLocal.setShared.begin()のポイントは何だったのでしょうか?そうでないと、そこに 'exportSets'の代わりに 'exportLocal'を入れようと思っていましたか?

要するに、問題はコーディングミスであり、再帰の問題ではないと思います。

補助メモ - 再帰ではなくループにする方法はありますか?ループはほぼで、常にであり、より簡単で分かりやすく、簡単にデバッグできます。

+0

実際には、ローカルのエクスポートセット、つまりexportlocalをexportSetにコピーしています。私はforループの中で1つのステートメントを見逃しました。 exportSets.setShared.insert(numId); はい私は反復的な方法を考える必要があります –

+0

その行を質問に入れる価値はありますか?そうすれば、exportLocalとexportSetsの関係を見ることができます。 –

1

申し訳ありません - 私は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(); 
    } 
} 
0

私は再帰があなたの問題と関係がありませんと思います。問題は、単に作成しているデータが大きいことです。反復的な解決策への移行はそれを助けません。すでに指摘したように、メモリ内の構造体に格納するのではなく、トラバースしながら出力を書き出します。

ただし、構造体全体ではなく、再帰呼び出しでポインタを渡すことで、スタック上の内容を最小限に抑えることができます。

+0

ディスクベースのアプローチでは、最大13GBのファイルをメモリに書き出すことができました。しかし、この限界を超えて失敗する –