pypyで高速化したらメモリリークしたお話
Pythonクラスを関数内で定義すると、pypyでの実行時にメモリリークが発生して実行速度が遅くなる。
以下のコードをPythonで実行する。
import time class Leak: def proc(self): class Inner: def something(self): i=1+1 for _ in range(10000): a=Inner() a.something() return class Safe: class Inner: def something(self): i=1+1 def proc(self): for _ in range(10000): a=Safe.Inner() a.something() return print("Safe:") a=Safe() for _ in range(5): s=time.time() for _ in range(100): a.proc() print(time.time()-s) print("Leak:") a=Leak() for _ in range(5): s=time.time() for _ in range(100): a.proc() print(time.time()-s)
Pythonなら結果はSafeでもLeakでも変わらない。
$ python3 pypybench.py Safe: 0.1891028881072998 0.1931455135345459 0.1875746250152588 0.18657183647155762 0.19033050537109375 Leak: 0.18032550811767578 0.18199753761291504 0.1795341968536377 0.1779332160949707 0.18030810356140137
Pypyで実行。
pypy3 pypybench.py Safe: 0.0041353702545166016 0.002458333969116211 0.0013346672058105469 0.0010471343994140625 0.0009150505065917969 Leak: 0.11974382400512695 0.2023618221282959 0.30752086639404297 1.0994617938995361 1.716996431350708
だんだん遅くなる。インスタンスをdelしても遅くなるので、クラス定義がクリーンアップされずに溜まっているご様子。
解決策としては、関数内でクラスを定義しないこと。