メモリを消費しているオブジェクトをチェック!
無駄にメモリを消費しているオブジェクトがないか、チェックしてみましょう。
環境 : Python3
特定のオブジェクトのサイズ(メモリ使用量)
※2017/11/5 : コメントのご指摘で気づいたので追加
オブジェクトのサイズは、 sys.getsizeof()
で取得できますが、listなどのコンテナ型オブジェクトは、実際に格納しているオブジェクトのサイズを取得できません。
そこで、Python公式ドキュメントで紹介されているように、以下のようなめんどくさい方法を取る必要があります。
[Python公式]
https://docs.python.jp/3/library/sys.html#sys.getsizeof
[リンク先: recursive sizeof recipe]
https://code.activestate.com/recipes/577504/
import sys
from itertools import chain
from collections import deque
def compute_object_size(o, handlers={}):
dict_handler = lambda d: chain.from_iterable(d.items())
all_handlers = {tuple: iter,
list: iter,
deque: iter,
dict: dict_handler,
set: iter,
frozenset: iter,
}
all_handlers.update(handlers) # user handlers take precedence
seen = set() # track which object id's have already been seen
default_size = sys.getsizeof(0) # estimate sizeof object without __sizeof__
def sizeof(o):
if id(o) in seen: # do not double count the same object
return 0
seen.add(id(o))
s = sys.getsizeof(o, default_size)
for typ, handler in all_handlers.items():
if isinstance(o, typ):
s += sum(map(sizeof, handler(o)))
break
return s
return sizeof(o)
# 実行
d1 = np.random.randint(0, 1000, (1000, 1000))
d2 = np.random.randn(1000, 1000)
d_list = [d1, d2]
print('sys.getsizeof(d1) :', sys.getsizeof(d1))
print('compute_object_size(d1, unit=0) :', compute_object_size(d1, unit=0))
print('sys.getsizeof(d_list) :', sys.getsizeof(d_list))
print('compute_object_size(d_list, unit=0) :', compute_object_size(d_list, unit=0))
sys.getsizeof(d1) : 8000112
compute_object_size(d1, unit=0) : 8000112.0
sys.getsizeof(d_list) : 80
compute_object_size(d_list, unit=0) : 16000304.0
一定のメモリサイズを超えるオブジェクト一覧
上の関数を使って、一定のメモリサイズを超えるオブジェクト一覧を表示します。
eval()
は、文字列を変数に変換する関数です。
globals()を対象にしている為、この関数をモジュール化してimportしても機能しません。開発中の確認用に、同一モジュール内で実行してください。
import numpy as np
import pandas as pd
def show_objects_size(threshold, unit=2):
"""
生きている全部の変数のサイズを表示する
Parameters
----------
threshold : int, float
表示するサイズの下限しきい値。
unitに応じた値にすること。
unit : int
表示するサイズの単位
1: KB
2: MB
3: GB
ex.
100MB超の変数をGB単位で表示したい場合
threshold=0.1, unit=3
Returns
-------
なし
"""
disp_unit = {0: 'bites', 1: 'KB', 2: 'MB', 3: 'GB'}
# 処理中に変数が変動しないように固定
globals_copy = globals().copy()
for object_name in globals_copy.keys():
size = compute_object_size(eval(object_name))
if size > threshold:
print('{:<15}{:.3f} {}'.format(object_name, size, disp_unit[unit]))
# 100MB超のオブジェクト一覧を表示する
show_object_size(100)
※Jupyter Notebookで記述するような、フラットな構成を想定して、global変数を拾っています。
train 2060.736 MB
test 749.182 MB
df_customer 443.340 MB
df_sales 238.667 MB
無駄なオブジェクトは削除
役目を終えた大きなサイズのオブジェクトは、メモリを圧迫しないように削除しておきましょう。
del train, test
# どれほど有効かわからないけど、適宜gc.collect()でガベージコレクションを強制実行。
import gc
gc.collect()
さいごに
Pandas.DataFrameについては、なぜメモリが増大してしまうのか、どう対処すればよいか等をこちらの記事に書きました。ご参考までに。
Pandas.DataFrameのメモリサイズを削減する(最大で8分の1) [Python]