この記事は、シアトルコンサルティング株式会社 Advent Calendar 2021の3日目の記事です。
こんにちは、シアトルコンサルティングの長岡です。
はじめに
業務で1000万件くらいのデータに対し、DB1のデータをマスタDBと比較し、一致したデータがあれば別名に変換しDB2へ出力するというようなプログラムを作成し実行した際に、OutOfMemoryError: GC Overhead limit exceededが発生し、現場メンバー揃って苦戦したのでその時のことを書いていこうと思います。
OutOfMemoryError: GC Overhead limit exceededとは
Javaのヒープ領域にオブジェクトを割り当てるための十分な空間がない時に発生するエラーです。
冒頭でも触れた通り、処理すべきデータ量が膨大な時に頻発します。
JavaプロセスがGCの実行時間の98%以上を費やし、各実行で2%未満のヒープしか回復されない場合に、このエラーをスローするように設定されているみたいです。
試した事
調べてみるとヒープ領域のデフォルトサイズが512MBみたいだったので、JVMの起動時に-Xmx3Gを指定して、実行してみました。
すると数時間動いた末に、再度OutOfMemoryError: GC Overhead limit exceededが発生しました。
スケジュールの関係上あまり余裕が無かった為、対応できませんでしたが、メモリリークが発生しない実装ができれば解決する話です。
結果
試行錯誤は早々に諦めてプログラムで扱うデータ数を指定して分割して実行することにしました。
調べてみると、100万件を過ぎたあたりからプログラムのスローダウンが始まり、処理速度がどんどん落ちている事が分かりました。
その為、プログラムを10個に分けて100万件ずつデータを扱うように修正し、同時進行でプログラムを実行し約1時間で無事データを変換することができました。
さいごに
今回はテストデータを作成する為に作成したプログラムだったので今回のような方法で穏当に解決しましたが、本番アプリケーションのプログラム内で同じようなことが発生した場合は今回のような対応ではなく、メモリリークが起きている原因を特定し、より良いプログラムに修正する必要があると思いました。
今回は1000万件のデータに対し、メモリリークを意識しない実装が原因で起きたエラーだったので、大量のデータを扱うプログラムを組む際はお気を付けください。