はじめに
大量のCSVやログなどを処理するとき、少量のデータでは動いていたプログラムが、データ量の増加によってメモリ不足になることがあります。原因の一つは、処理対象を一度にメモリへ読み込み、同時に保持するデータ量が大きくなることです。
メモリ不足を防ぐには、すべてを一括で読み込む方法だけでなく、必要な分だけ順番に読む「逐次読み込み」や、一定件数ごとに読む「チャンク読み込み」を使い分けます。この記事では、一括読み込みと逐次・チャンク読み込みの違いを整理し、どの方法を選べばよいかを解説します。
一括読み込みと逐次読み込みの違い
一括読み込みと逐次読み込みの主な違いは、処理対象のうち「どれだけを同時にメモリへ保持するか」です。メモリ使用量だけでなく、処理内容や実装のしやすさも含めて選びます。
| 方法 | 同時に保持するデータ | 向いている場面 | 主な注意点 |
|---|---|---|---|
| 一括読み込み | 処理対象の全体 | データ全体を使う処理、十分に小さいデータ | データ量が増えると必要メモリも増えやすい |
| 逐次読み込み | 1件や1行など必要な範囲 | 各データを順番に独立して処理できる場合 | 結果を全件保持するとメモリ削減効果が小さくなる |
| チャンク読み込み | 一定件数・一定サイズ | メモリを抑えつつ複数件をまとめて処理したい場合 | チャンクサイズを処理内容と利用可能メモリに合わせる必要がある |
「一括読み込みは速く、逐次読み込みは遅い」と単純には決められません。実際の処理時間は、ストレージのI/O、バッファリング、データ変換、処理内容、チャンクサイズなどによって変わります。まずはメモリへ同時に保持する量を整理し、そのうえで実測して判断することが重要です。
一括読み込みとは
一括読み込みは、処理対象となるデータを最初にまとめてメモリへ読み込んでから処理する方法です。データ全体を配列やリストとして扱えるため、実装を理解しやすく、全件を使った計算や比較を行いやすい利点があります。
一方、ファイルサイズが大きくなると、読み込んだデータだけでなく、解析後のオブジェクトや文字列、加工途中のコピーなどにもメモリが使われます。そのため、ファイルが1GBだから必要メモリも1GBとは限りません。データ量が増えるほど、一括読み込みが利用可能メモリを圧迫しやすくなります。メモリがどのように確保・利用されるかという基礎は、メモリ管理とは?プログラムの性能を左右する仕組みを基礎から解説で整理しています。
逐次読み込みとは
逐次読み込みは、1行や1件など必要な範囲だけを読み込み、処理が終わったら次のデータへ進む方法です。例えば、大きなCSVを1行ずつ読み、条件に合う行だけ集計する処理であれば、ファイル全体をメモリへ保持する必要はありません。
ただし、逐次読み込みに変えるだけでメモリ使用量が必ず一定になるわけではありません。処理済みのデータや結果をリストへ追加し続ければ、保持するデータは増えていきます。メモリを抑えるには、読み込み方だけでなく「処理後に何を保持するか」も合わせて設計する必要があります。
なお、この記事で扱う逐次読み込みは、有限のファイルや検索結果などを少量ずつ読む方法です。データ基盤でいう「ストリーム処理」は、継続的に到着・更新されるデータを扱う文脈を含むため、本記事では逐次読み込みと同義語として扱いません。
チャンク読み込みとは
チャンク読み込みは、1件ずつではなく、例えば1000件や10MBなど一定のまとまりごとに読み込んで処理する方法です。一括読み込みより同時保持量を抑えながら、複数件をまとめて処理できるため、大量データでは実用的な選択肢になります。
チャンクを大きくすれば1回で処理できる件数は増えますが、その分だけメモリ使用量も増えます。逆に小さくしすぎると、読み込みや処理の呼び出し回数が増える場合があります。固定の正解値があるわけではなく、利用可能なメモリと処理時間を計測しながら調整します。
どの読み込み方法を選ぶか
判断の出発点は、データ量そのものではなく「処理中に同時保持する必要がある量」です。データ全体が十分に小さく、全件を使う処理が必要なら一括読み込みが分かりやすい場合があります。各行を独立して変換・抽出できるなら逐次読み込み、複数件をまとめて処理したいならチャンク読み込みが候補になります。
- 全データを同時に保持する必要があるか
- 1件ずつ処理して結果だけを残せるか
- 一定件数ごとに処理を区切れるか
- 処理途中のコピーや結果を必要以上に保持していないか
データ量を増やしたときだけメモリ不足になる場合は、読み込み方法だけでなく、中間データやコピーも確認します。症状から確認箇所を絞る手順は、プログラムの型・メモリトラブルを切り分ける方法|原因別の確認ポイントを解説で確認できます。
全件を使う処理では読み込み方法だけで解決しない
逐次・チャンク読み込みが効果を発揮しやすいのは、各データを処理した後に捨てられる、または小さな集計結果だけを残せる場合です。全件を並べ替える、全データ同士を比較する、巨大な結果をそのまま保持するといった処理では、読み込みを分割しても別の場所で大きなメモリが必要になることがあります。
そのような場合は、処理を複数段階へ分ける、外部ストレージやデータベース側で処理する、途中結果をファイルへ退避するなど、読み込み方法とは別の設計が必要です。この記事では個別の実装方法までは扱わず、まず「同時にメモリへ保持する量を減らせる処理か」を見極めることを基本とします。
まとめ
大量データ処理でメモリ不足を防ぐには、データを一度に読み込むかどうかではなく、処理中にどれだけのデータを同時に保持する必要があるかを考えることが重要です。一括読み込みは全体を扱いやすい一方、データ量に応じてメモリ使用量が増えやすくなります。逐次読み込みは必要な範囲だけを順番に扱い、チャンク読み込みは一定のまとまりで処理することで、同時保持量を調整できます。
ただし、逐次・チャンク読み込みでも処理結果を全件保持すればメモリは増えます。また、処理速度は読み込み方式だけでは決まりません。まず全件保持が必要かを確認し、分割できる処理では逐次・チャンク読み込みを候補にして、実際のメモリ使用量と処理時間を計測しながら選びましょう。