4

私が働いている私の場所では、ファイルごとに100万行を超えるファイルがありました。サーバーのメモリは10GBを超え、JVMは8GBですが、サーバーがしばらくハングして他のタスクを停止することがあります。

コードのプロファイルを作成したところ、ファイル読み取りメモリの使用量がギガバイト単位で頻繁に増加し(1GBから3GB)、その後突然正常に戻ることがわかりました。この頻繁な高メモリ使用と低メモリ使用により、サーバーがハングするようです。もちろん、これはガベージコレクションによるものです。

パフォーマンスを向上させるためにファイルを読み取るには、どのAPIを使用する必要がありますか?

今、私はBufferedReader(new FileReader(...))これらのCSVファイルを読み取るために使用しています。

プロセス:ファイルをどのように読み取っていますか?

  1. 私はファイルを1行ずつ読みます。
  2. すべての行にはいくつかの列があります。それに応じて解析するタイプに基づいて(doubleのコスト列、intのvisit列、Stringのキーワード列など)。
  3. 適格なコンテンツ(visit> 0)をHashMapにプッシュし、最後にタスクの最後にそのMapをクリアします

アップデート

私はこの30または31ファイル(1か月のデータ)の読み取りを行い、適格なものをマップに保存します。後でこのマップを使用して、さまざまなテーブルの犯人を取得します。したがって、読み取りは必須であり、そのデータの保存も必須です。HashMapの部分をBerkeleyDBに切り替えましたが、ファイルを読み取るときの問題は同じか、さらに悪いです。

4

3 に答える 3

10

BufferedReaderは、これに使用する2つの最適なAPIの1つです。ファイルの読み取りで本当に問題が発生した場合は、NIOにあるものを使用してファイルをメモリマップし、メモリから直接内容を読み取ることもできます。

しかし、あなたの問題は読者にありません。あなたの問題は、すべての読み取り操作がたくさんの新しいオブジェクトを作成することです。おそらく、読み取り直後に行うものに含まれます。

作成するオブジェクトの数やサイズを減らすことを念頭に置いて入力処理をクリーンアップするか、不要になったオブジェクトをより迅速に削除することを検討する必要があります。処理のためにすべてをメモリに吸い込むのではなく、一度に1行またはチャンクでファイルを処理することは可能でしょうか?

もう1つの可能性は、ガベージコレクションをいじることです。2つのメカニズムがあります。

  • ガベージコレクターを時々明示的に呼び出します。たとえば、10秒ごとまたは1000入力行ごとなどです。これにより、GCによって実行される作業量が増加しますが、各GCにかかる時間は短くなり、メモリはそれほど膨張しないため、サーバーの他の部分への影響が少なくなることを願っています。

  • JVMのガベージコレクタオプションをいじってください。これらはJVM間で異なりますが、java -Xいくつかのヒントが得られるはずです。

更新:最も有望なアプローチ:

処理のために一度にデータセット全体をメモリに入れる必要が本当にありますか?

于 2009-11-28T13:59:57.687 に答える
5

コードのプロファイルを作成したところ、ファイル読み取りメモリの使用量がギガバイト単位で頻繁に増加し(1GBから3GB)、その後突然正常に戻ることがわかりました。この頻繁な高メモリ使用と低メモリ使用により、サーバーがハングするようです。もちろん、これはガベージコレクションによるものです。

使用してBufferedReader(new FileReader(...))もそれは発生しません。

問題は、行/行を配列またはリストに読み込んで処理してから、配列/リストを破棄していることだと思います。これにより、メモリ使用量が増加し、その後再び減少します。この場合、各行/行を読み取るときに処理することで、メモリ使用量を減らすことができます。

編集:問題は、メモリ内のファイルコンテンツを表すために使用されるスペースに関するものであることに同意します。巨大なメモリ内ハッシュテーブルの代わりに、コンピュータメモリがキロバイト単位で測定されたときに使用した古い「ソートマージ」アプローチに戻ることもできます。(処理は、関連する行Rを取得するためにキーKを使用してルックアップを実行しているステップによって支配されていると想定しています。)

  1. 必要に応じて、各入力ファイルを前処理して、キーKでソートできるようにします。

  2. 効率的なファイルソートユーティリティを使用して、すべての入力ファイルをKで順番にソートします。従来のマージソートアルゴリズムを使用するユーティリティを使用します。これにより、各ファイルがメモリ内で並べ替え可能な小さなチャンクに分割され、チャンクが並べ替えられ、一時ファイルに書き込まれてから、並べ替えられた一時ファイルがマージされます。UNIX/Linuxsortユーティリティは良いオプションです。

  3. ソートされたファイルを並行して読み取り、すべてのファイルから各キー値に関連するすべての行を読み取り、それらを処理してから、次のキー値に進みます。

実際、BerkeleyDBを使用しても効果がなかったことに少し驚いています。ただし、プロファイリングでDBの構築にほとんどの時間が費やされていることがわかった場合は、DBを構築する前に、入力ファイル(上記のように!)をキーの昇順で並べ替えることで速度を上げることができる場合があります。(大きなファイルベースのインデックスを作成する場合、エントリをキー順に追加するとパフォーマンスが向上します。)

于 2009-11-28T13:58:23.273 に答える
1

gcを調整する(そしていくつかのgc印刷を行う)ために、次のvmオプションを使用してみてください。

-verbose:gc -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
于 2011-04-05T05:23:01.327 に答える