2009-04-12 13 views
12

openstreetmap xmlファイルを取り込み、通常は元のサイズの約10%のバイナリランタイムレンダリング形式に変換するコンバータを作成しました。入力ファイルのサイズは通常3GB以上です。入力ファイルは一度にすべてメモリにロードされませんが、ポイントとしてストリームされ、ポリスが収集され、bspが実行され、ファイルが出力されます。最近、大容量のファイルでは、メモリが使い果たされ、死んでしまいます(問題のファイルは1400万ポイントと100万ポリゴンあります)。通常、私のプログラムは、これが起こったときに約1gbから1.2gbのRAMを使用しています。私は2から8ギガバイト(XPで)に仮想メモリを増やしてみましたが、この変更は効果がありませんでした。また、このコードはオープンソースなので、使用可能なRAM(遅くても)に関係なく動作させたい、Windows、Linux、Mac上で動作します。メモリ使用量の多いアプリケーションでメモリが不足しないようにするにはどうすればよいですか?

メモリが不足するのを防ぐためにどのようなテクニックを使用できますか?より小さなサブセットでデータを処理し、最終結果をマージするか?自分の仮想メモリタイプのハンドラを使用していますか?他のアイデア?

答えて

14

まず、32ビットシステムでは、ページファイルの設定に関係なく、常に4 GBのメモリに制限されます。 (これらのうち、2GBしかWindows上でプロセスに利用できません.Linuxでは、通常3GB程度の空き容量があります)

最初の明らかな解決策は、64ビットOSに切り替えて、 64ビット版のアプリケーション。これはあなたに巨大な仮想メモリ空​​間を提供し、OSは必要に応じてデータをページファイルの内外にスワップして動作させます。

第2に、一度に小さなチャンクを割り当てることが役に立ちます。 1GBのチャンクより256MBの空きメモリが4つ見つかることがよくあります。

第3に、問題を分割します。一度にデータセット全体を処理するのではなく、一度に小さなセクションだけをロードして処理してください。

+0

Windowsは/ LARGEADDRESSAWAREを使用して3GBの仮想空間を持つことができます –

+0

OSが提供できる*場合、このフラグを使用すると、プロセスは最大4GB *を使用できます。通常、Windowsは各プロセスに2GBしか与えないように設定されています。それはドライバの不安定性のリスクで、あなたも3GBを与えるために変更することができます。 PAEを使用すると、さらに多くの情報を得ることができます。しかし、64ビットはおそらくより良い賭けです。 – jalf

+1

Imho、3番目のオプションが最も重要です。メモリを制御するだけでなく、並列処理も可能です。 – xtofl

4

SAXというXML処理(XMLの読み込みは一度に行うのではなく)に基づいているようです。

解決策はほとんどの場合アルゴリズムを変更して、問題をより小さな部分に分割します。物理的に一度に多くのメモリを割り当てずに、必要なものだけを読み込み、処理してから書き出します。

アルゴリズムで必要なときにハードドライブを使用してメモリを拡張することがあります。

アルゴリズムを分割できない場合は、おそらくmemory mapped filesのようなものが必要です。

Windowsシステムを使用している場合は、最悪の場合、VirtualAllocのようなものを使用できます。 32ビットシステムの場合は、Physical Address Extension (PAE)のようなものを使うことができます。

また、プログラムの入力制限を設定し、32ビットおよび64ビットシステムでは異なる制限を設定することもできます。

4

どこにもメモリが漏れていないことを確認しましたか?

あなたのプログラムはLinuxに移植可能であるため、Valgrindの下で実行してください。

+0

はい私はリークをチェックしましたが、何もありません。 – KPexEA

0

txtをバイナリの会話にしているように聞こえるので、なぜデータ全体をメモリに保存する必要がありますか?
txt(xml)からプリミティブを読み込んでbinarystreamに保存できませんか?

2

Windows XPを使用していると仮定すると、メモリ制限を超えているだけで、上記のようにコードを修正したくない場合は、boot.iniファイルに/ 3GBスイッチを追加してからリンカスイッチを設定して余分な1GBのメモリを確保するだけです。

+0

3GBを使用するのはそれほど簡単ではありません。ポインタの操作が安全であることを確認する必要があります。そうしないと、メモリ使用率が高くなるとクラッシュします。詳細については、http://blogs.msdn.com/oldnewthing/archive/2004/08/12/213468.aspxを参照してください。 – eran

3

あなたのメモリの問題は、メモリにBSPツリーを保持していると思われます。したがって、BSPをディスク上に保ち、いくつかのチャンクをメモリ内に保持するだけです。これは、構造が他のいくつかのツリー構造よりも優れているので、BSPではかなり簡単になり、ロジックは単純でなければなりません。効率的でメモリに優しいためには、キャッシュサイズが使用可能なメモリに設定されたキャッシュを使用して、キャッシュ空きフラグを持つことができます。

1

実際のメモリ(Windowsではワーキングセットと呼ばれています)はメモリですが、使用している仮想メモリの容量は予約した総容量であるという点で、仮想メモリは「RAM」とは異なります。実際に変更またはロックされている

他の人が指摘しているように、32ビットWindowsプラットフォームでは、特別なフラグを3ギガバイトに設定しない限り、仮想メモリの制限は2ギガバイトです。コード内のすべてのポインタと、署名されていないポインタを使用します。

ユーザーを強制的に64ビットにしたり、仮想メモリを監視したり、最大ブロックサイズを32ビットオペレーティングシステムの制限内に収まるように上限を設定することは私の助言になります。

私はWindowsで32ビットの壁にぶつかってきましたが、Linuxのこれらの制限を回避する経験はありませんでしたので、Windowsの側面についてのみ説明しました。

1

32ビットXPでは、プログラムの最大アドレス空間は2GBです。次に、DLLとドライバがアドレス空間に読み込まれるために断片化が発生します。最後に、ヒープが断片化するという問題があります。

64ビットシステムで64ビットプロセスとして実行して実行するのが一番良い方法です。突然これらの問題はすべて消え去る。より良いヒープを使用してヒープフラグメンテーションの影響を緩和することができます。また、VirtualAllocを使用して、1つの大きな連続したチャンクでメモリを取得してから、DLL /ドライバの断片化を防ぐことができます。

最後に、プロセス間でBSPを分割できます。複雑で痛い、そして率直に言って、ディスクに置くのは簡単ですが、理想的には、すべてのプロセスを常駐させることができれば、プロセスのグループに情報を交換させることで、より良いパフォーマンスを得ることができます(OSよりも、ファイルのバッファリングを処理することができます...これは大きな場合です)。各プロセスで必要なメモリはずっと少なくて済み、したがって2GBのアドレス空間の制限に達するべきではありません。もちろん、あなたはRAM /スワップをすばやく燃やすでしょう。

小さいチャンクを割り当てることで、アドレススペースの断片化の影響を緩和できます。これには別の厄介な副作用がありますが、割り振りに失敗した場合は、より小さいメモリチャンクを取得するバックオフポリシーに従うことができます。頻繁にこのシンプルなアプローチは、そうでない場合に動作するプログラムを取得しますが、残りの時間は可能な限り実行します。

男の子、64ビットコンピューティングは、他の選択肢よりもずっとうれしいですね。

1

どのようにポイントのためのメモリを割り当てていますか?一度に1つずつポイントを割り当てていますか(たとえば、 pt =新しいポイント)。ポイントのサイズによっては、メモリが無駄になることがあります。たとえば、Windowsのメモリは16バイトの倍数で割り当てられるため、1バイトを割り当てようとしてもOSは実際に16バイトを割り当てます。

この場合、メモリアロケータを使用すると役立ちます。 STLアロケータを使用して簡単にチェックできます。 (Pointクラスのnew演算子をオーバーロードし、STLアロケータを使用して 'malloc'またはデフォルトのnew演算子ではなくメモリを割り当てます)。

+0

ヒープマネージャーを使用してポイントとポリスを割り当てているので、ヒープが(この場合)1MBのチャンクと各チャンクからのリクエストを割り当てているので、必要なスペースしか取らず、ほとんど聞き取れません。 – KPexEA

+0

もう一つの理由は、 (つまり、メモリは小さな塊で利用できますが、 '1Mb'を求めるとき、連続した1MBのチャンクは利用できません) XMLパーサーは 'ヒープマネージャ'を使用していますか?断片化? –

0

メモリサイズに依存しない場合は、サイズに依存しないアルゴリズムが必要です。あなたのRAMがどんなサイズであっても、あなたがコントロールしているメモリ使用量を持っていなければ、あなたはボーダーにぶつかるでしょう。

出力のビットを生成するために使用する可能性がある情報のうち、最も小さな情報を見てみましょう。次に、入力をこのサイズのチャンクに分割する方法について考えてみましょう。

今は簡単ですね。 (うまくいけないのはうれしいよ:))

1

あなたは最適な方法でメモリを割り当てたり、割り当てを解除したりすることはできません。他の人が指摘しているように、あなたは記憶を漏らし、それを知らないかもしれません。デバッグとメモリ割り当ての最適化には時間がかかります。

メモリ使用量の最適化に時間を費やしたくない場合は、Conservative Garbage Collectorを試してみてはいかがですか?これはmalloc()/ newとfree()のプラグイン置換えです。実際、free()はノーオペレーションなので、プログラムからそれらの呼び出しを削除することができます。その代わりに、あなたのプログラムを手作業で最適化し、以前提案されたようにメモリプールを管理するならば、CGCがすでにあなたのためにしている多くの作業を終わらせるでしょう。

1

あなたの出力とあなたの入力をストリーミングする必要があります。出力形式がストリーム指向でない場合は、2回目の処理を行うことを検討してください。たとえば、出力ファイルがデータのチェックサム/サイズで始まる場合は、最初のパスにスペースを残し、後でそのスペースにシーク/ライトします。

0

64ビットマシンに切り替える必要はなく、他の人が示唆する1000ものもののほとんどを必要としません。あなたが必要とするものは、より慎重なアルゴリズムです。 Windowsであれば、ファイルの地図(sample code)を利用

  • は、ここでは、このような状況を手伝うために行うことができますいくつかのものです。これにより、メモリ内のファイル全体を読み取っているかのように、単一のバッファポインタを介してファイルにアクセスできます。 Linuxカーネルの最近のバージョンも同様のメカニズムを持っています。

  • できる場合は、ファイルを順番にスキャンし、メモリ内DOMを作成しないようにします。これにより、ロード時間とメモリ要件が大幅に削減されます。
  • プールメモリを使用してください!おそらく、ノード、ポイント、その他のような小さなオブジェクトがたくさんあります。プールされたメモリを使用して(私はあなたが管理されていない言語を使用していると仮定しています。プールされた割り当てとメモリプールを検索してください)。
  • 管理言語を使用している場合は、少なくともこの特定の部分をアンマネージ言語に移行し、メモリとファイルの読み取りを制御します。管理された言語は、メモリー占有量とパフォーマンスの両方で軽微なオーバーヘッドを伴います。 (はい、これは「C++」というタグが付いていることを知っています)
  • 一度に最小量のデータのみを読み込んで処理するインプレイスアルゴリズムを設計しようとすると、メモリ要件が低下します。

最後に、複雑な作業には複雑な手段が必要であることを指摘しておきます。8GBのRAMを搭載した64ビットマシンを買う余裕があると思うのであれば、「メモリにファイルを読み込み、データを処理し、出力を書き込む」アルゴリズムを使用して、完了までに1日かかる場合でも使用してください。

0

そこには、いくつかのインスタンスをファイルに保存し、使用する必要があるときにそれらを取得した後に、そのための良いテクニックがあります。

この手法は、大量のメモリが必要な場合にスケーラブルになるように、Doxygenのような多くのオープンソースソフトウェアで使用されています。

0

私は最近、同じことをやったので、これは、古い質問ですが....

には単純な答えはありません。理想的な世界では、巨大なアドレス空間(つまり64ビット)を持つマシンと大量の物理メモリを使用します。巨大なアドレス空間だけでは十分ではありません。その場合、XMLファイルをデータベースに解析し、適切なクエリを使用して、必要なものを取り出します。おそらく、これはOSM自体が行うことです(私は世界が約330GBと信じています)。

実際には、私はまだ便宜のためにXP 32bitを使用しています。

スペースとスピードのトレードオフです。どれくらい時間がかかっても気にしないなら、どんな量のメモリでもほとんど何でもできます。 STL構造体を使用すると、必要なものを解析できますが、すぐにメモリ不足になります。スワップする独自のアロケータを定義することはできますが、マップ、ベクター、セットなどは実際にあなたが何をしているのかわからないので、やはり効率が悪いでしょう。

私が32ビットマシンで小さなフットプリントで動作させるために見つけた唯一の方法は、自分が何をやっていたか、タスクを塊にするときに必要なことを非常に注意深く考えることでした。メモリは効率的です(〜100MB以上を使用することはありませんが、大規模ではありませんが、XMLデータを解析する頻度は重要です)。

関連する問題