最高のパフォーマンスを得るためにファイルの読み取りに使用するJavaのAPIはどれですか?

StackOverflow https://stackoverflow.com/questions/1812565

質問

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

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

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

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

プロセス:ファイルの読み取り方法

  1. ファイルを1行ずつ読み取ります。
  2. すべての行には列がほとんどありません。タイプに応じて、それらを対応して解析します(二重のコスト列、intの訪問列、文字列のキーワード列など)。
  3. HashMapで適格なコンテンツ(visit> 0)をプッシュし、タスクの最後にそのマップを最終的にクリアします

更新

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

役に立ちましたか?

解決

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

しかし、問題は読者にありません。あなたの問題は、すべての読み取り操作が新しいオブジェクトの束を作成することです。ほとんどの場合、読み取り直後に行うことです。

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

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

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

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

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

処理のために一度にメモリ内のデータセット全体を本当に必要としますか

他のヒント

  

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

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

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

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

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

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

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

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

gcを調整するために次のvmオプションを使用してみてください(およびgc印刷を行います):

-verbose:gc -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top