プログラムがメモリを使い始め、どこに問題があるかを調べようとすることがあります。
こんなとき役に立つ、さまざまなツールがあります。ここでは、 Pympler lib
の、asizeof
というシンプルなツールをご紹介したいと思います。
Pymplerには、Pythonオブジェクトのメモリ動作を測定、監視、分析するための2つの追跡手段があります。
muppy
とClass Tracker
です。
これが、メモリの漏れを調べるのに、役立ちます。
純粋なPythonオブジェクトのサイズだけを返す、組み込みの sys.getsizeof()
というメソッドがあります。
例えば、このように使います。
>>> import sys
>>> sys.getsizeof(None)
16
>>> sys.getsizeof([])
64
>>> sys.getsizeof('a')
50
>>> sys.getsizeof(['a'])
72
>>> sys.getsizeof(['avadakedavra'])
72
対照的に、 asizeof.asizeof()
は内部的な値を再帰的に検索し、
内部に含まれるオブジェクトのサイズを含む全体のサイズを数えます。
>>> from pympler import asizeof
>>> asizeof.asizeof(None)
16
>>> asizeof.asizeof([])
64
>>> asizeof.asizeof('a')
56
>>> asizeof.asizeof(['a'])
128
>>> asizeof.asizeof(['avadakedavra'])
136
スクリプト内の変数の大きさを調べることで、 asizeof
を使ってボトルネックを見つけることができるというわけです。
複雑で入り組んだスクリプトでは、もっと便利なツールが必要になるかもしれませんが、小さなスクリプトでは asizeof
が便利です。
Asizeof
は、どの変数が問題になるかを直感的に推測し、そのサイズを確認し、直感を確認するときに使用できます。
しかし、問題がどこにあるのか分からず、問題のあるコードが数十から数百行に及ぶ場合は、
すべての変数に print(asizeof())
を書くことはできないので、メモリプロファイラを使うのが良いでしょう。
例:
from pympler import asizeof
class Empty(object):
pass
class Dummy(object):
def __init__(self):
self.a = ['apple', 'banana', ['foo', 'bar', ['tiger', 'leo']]]
self.b = {'key1': 'val1', 'key2': 'val2'}
self.c = bytearray(1024*1024*4)
self.d = self
def investigated_function():
sometuple = (4, 10, -2,)
for i in range(1000):
empty = Empty()
dummy = Dummy()
# do_something_with(dummy)
investigated_function()
を実行すると、メモリが消費され、問題がどこにあるか調べることになります。
そうすると、変数をチェックするだけです。例えば:
print( asizeof.asizeof(sometuple) )
print( asizeof.asizeof(empty) )
print( asizeof.asizeof(dummy) )
168
152
4195944
その問題が、4,195,944バイト(約4Mb)のdummy
インスタンスにあることがわかります。
また、 asizeof.asizesof
(plural, "A Sizes Of") 関数を使うこともできます。
print( asizeof.asizesof(dummy.a, dummy.b, dummy.c, dummy.d) )
# returns sizes of individual values
(592, 512, 4194368, 472)
上のコマンドから、 Dummyクラスの属性 dummy.c
が、多くのメモリを使っていることがわかります。
self.c = bytearray(1024*1024*4)