🐈

「Out of Memory」が出て困ったので、大量データの扱い方をイチから学んでみた

2024/12/06に公開

最近、データ処理のプログラムを書いている中で「Out of Memory(メモリ不足)」というエラーに遭遇しました。このエラー、初めて見ると「一体何が原因?」「どこが問題だったの?」と困ってしまいますよね。私も同じ状況でした。

この記事では、私がメモリ不足の問題を調べて理解した内容を共有します。どのくらいのデータが「大きすぎる」のか、どうすれば効率的に処理できるのか、初心者目線でまとめてみたので、同じような悩みを抱えている方に役立てば嬉しいです。


1. Out of Memory(メモリ不足)とは?

プログラムが実行中に必要なメモリ量が、システムの持つ物理メモリや仮想メモリの容量を超えてしまうと、「Out of Memory(OOM)」エラーが発生します。この状態は、パソコンの部屋(メモリ)に入りきらないほどの人(データ)が押し寄せるようなものです。

現代のメモリ容量の目安

デバイス メモリ容量の目安
PCやノートPC 8GB~16GB
サーバー 32GB~512GB(場合によっては1TB以上)

どのくらいのデータがOOMを引き起こすのか?

例えば、Pythonで100億個の整数を持つリストを作成すると、リスト全体のサイズは約280GBに達します。これは、一般的なPCの物理メモリを遥かに超えるサイズです。


2. rangeとリスト:メモリの使い方の違い

Pythonでは、大量のデータを扱うときにlistrangeを使い分けることが重要です。この2つは一見似ていますが、メモリの使い方が全く異なります。

リストは全データを展開する

l = list(range(10**10)) # メモリに全てのデータを展開

このコードでは、リスト全体がメモリにロードされるため、メモリ不足になりやすいです。

rangeは必要なときにデータを生成する

r = range(10**10) # スタート、ストップ、ステップのみを保持

一方でrangeは、全てのデータを保持せず、必要なときにデータを逐次生成します。このため、range自体が消費するメモリはごくわずかです。


3. 実際のデータ処理で気をつけるポイント

(1) 一度に全てを処理しない

大規模なデータを扱う際は、分割して少しずつ処理する方法が効果的です。以下の例では、データを100万個ずつ処理しています。

for i in range(0, 1010, 106): # 100万個ずつ
    chunk = range(i, i + 10**6) # 必要な部分だけ生成
    for num in chunk: process(num) # 個別の処理を実行

(2) NumPyで効率化

Pythonリストよりもメモリ効率の良いデータ構造を使うのも有効です。たとえば、NumPyの配列を使うと、整数をint32型にすることでメモリ使用量を大幅に削減できます。

import numpy as np

array = np.arange(10**10, dtype=np.int32)
print(array.nbytes / 1e9) # 約40GB

(3) ストリーム処理を活用

データベースや外部ストレージにデータを保存し、必要な部分だけを読み込んで処理する方法も検討しましょう。

with open('large_file.csv', 'r') as file:
    for line in file:
        process(line) # 1行ずつ処理

4. メモリ消費を確認する方法

Pythonでメモリ消費量を確認したいときは、sys.getsizeofを使うと便利です。以下はrangeとリストの比較例です。

import sys

r = range(10**10)
print("Range size:", sys.getsizeof(r)) # 非常に小さい
try:
    l = list(range(10**10))
    print("List size:", sys.getsizeof(l))
except MemoryError:
    print("MemoryError: リストは大きすぎます")

この結果から、rangeの効率性が実感できます。


5. OOMを避けるためのベストプラクティス

方法 説明
データを分割して処理する 必要なデータだけを少しずつ処理する
効率的なデータ構造を使う NumPyやジェネレーターなどを活用する
データベースや外部ストレージを利用する メモリに全て載せるのではなく、ファイルやDBから部分的に読み込む
メモリ消費を事前に確認する 小さなデータセットでテストして、想定外のメモリ使用を防ぐ

まとめ

今回、Out of Memoryエラーをきっかけに、データ処理やメモリの効率的な使い方を学びました。以下のことがわかりました。

  • 大量データを扱う際は、一度に全てを処理しないことが重要。
  • rangeやNumPyのような効率的なツールを活用すると、メモリ消費を抑えられる。
  • 外部ストレージやストリーム処理で、大規模データにも対応可能。

私自身まだまだ学びの途中ですが、こうして知識を整理し共有することで、さらに理解が深まったように感じます。同じようにデータ処理やメモリ問題に悩んでいる方の助けになれば嬉しいです!

Discussion