Pandas: サイクリックGCの問題

作成日 2013年01月08日  ·  14コメント  ·  ソース: pandas-dev/pandas

間もなくデバッグされる謎:

import pandas as pd
import numpy as np

arr = np.random.randn(100000, 5)

def leak():
    for i in xrange(10000):
        df = pd.DataFrame(arr.copy())
        result = df.xs(1000)
        # result = df.ix[5000]

if __name__ == '__main__':
    leak()
Bug

最も参考になるコメント

記録のために、私たち(+ @ sbneto)はこれを少しの間推定に使用しており、非常にうまくやっています:

# monkeypatches.py

# Solving memory leak problem in pandas
# https://github.com/pandas-dev/pandas/issues/2659#issuecomment-12021083
import pandas as pd
from ctypes import cdll, CDLL
try:
    cdll.LoadLibrary("libc.so.6")
    libc = CDLL("libc.so.6")
    libc.malloc_trim(0)
except (OSError, AttributeError):
    libc = None

__old_del = getattr(pd.DataFrame, '__del__', None)

def __new_del(self):
    if __old_del:
        __old_del(self)
    libc.malloc_trim(0)

if libc:
    print('Applying monkeypatch for pd.DataFrame.__del__', file=sys.stderr)
    pd.DataFrame.__del__ = __new_del
else:
    print('Skipping monkeypatch for pd.DataFrame.__del__: libc or malloc_trim() not found', file=sys.stderr)

全てのコメント14件

わかりました、これは一言で言えば、めちゃくちゃです。 gc.collectをforループに追加すると、メモリリークが停止します。

import pandas as pd
import numpy as np
import gc

arr = np.random.randn(100000, 5)

def leak():
    pd.util.testing.set_trace()
    for i in xrange(10000):
        df = pd.DataFrame(arr.copy())
        result = df.xs(1000)
        gc.collect()
        # result = df.ix[5000]

if __name__ == '__main__':
    leak()

ここには、サイクリックGCの実行時にのみガベージコレクションが行われるオブジェクトがあります。 ここでの解決策は何ですか、Pythonメモリアロケータが私たちを台無しにするのをやめるように__del__明示的にサイクルを中断しますか?

あなたはこれを試すことができます:

from ctypes import cdll, CDLL

import pandas as pd
import numpy as np

arr = np.random.randn(100000, 5)

cdll.LoadLibrary("libc.so.6")
libc = CDLL("libc.so.6")

def leak():
    for i in xrange(10000):
        libc.malloc_trim(0)
        df = pd.DataFrame(arr.copy())
        result = df.xs(1000)
        # result = df.ix[5000]

if __name__ == '__main__':
    leak()

これはPythonとは何の関係もないと思いますが、それで確認できます。

ええ、それはトリックをするようでした。 IPythonで実行した後のメモリ使用量は450MBで、malloc_trimは400MBを解放しました。 非常に有害

アップストリームのmalloc_trimリードに続いて、これはglibcの最適化がうまくいかなかったように見えます。
外部参照:
http://sourceware.org/bugzilla/show_bug.cgi?id=14827

「fastbins」コメントを参照してください。

In [1]: from ctypes import Structure,c_int,cdll,CDLL
   ...: class MallInfo(Structure):   
   ...:     _fields_ =[
   ...:               ( 'arena',c_int ),  #  /* Non-mmapped space allocated (bytes) */
   ...:            ('ordblks',c_int  ),# /* Number of free chunks */
   ...:            (    'smblks',c_int ),  # /* Number of free fastbin blocks */
   ...:            (    'hblks',c_int  ),  #/* Number of mmapped regions */
   ...:            (    'hblkhd' ,c_int ), #/* Space allocated in mmapped regions (bytes) */
   ...:            (    'usmblks' ,c_int), # /* Maximum total allocated space (bytes) */
   ...:            (    'fsmblks' ,c_int) ,#/* Space in freed fastbin blocks (bytes) */
   ...:            (    'uordblks' ,c_int),# /* Total allocated space (bytes) */
   ...:            (    'fordblks',c_int ),# /* Total free space (bytes) */
   ...:            (    'keepcost',c_int )# /* Top-most, releasable space (bytes) */
   ...:          ]
   ...:     def __repr__(self):
   ...:         return "\n".join(["%s:%d" % (k,getattr(self,k)) for k,v in self._fields_])
   ...: 
   ...: cdll.LoadLibrary("libc.so.6")
   ...: libc = CDLL("libc.so.6")
   ...: mallinfo=libc.mallinfo
   ...: mallinfo.restype=MallInfo
   ...: libc.malloc_trim(0)
   ...: mallinfo().fsmblks
Out[1]: 0

In [2]: import numpy as np
   ...: import pandas as pd
   ...: arr = np.random.randn(100000, 5)
   ...: def leak():
   ...:     for i in xrange(10000):
   ...:         df = pd.DataFrame(arr.copy())
   ...:         result = df.xs(1000)
   ...: leak()
   ...: mallinfo().fsmblks
Out[2]: 128

In [3]: libc.malloc_trim(0)
   ...: mallinfo().fsmblks
Out[3]: 0

その後は修正されません。 たぶん、mallocトリミングを行うために、いつかパンダにいくつかのヘルパー関数を追加する必要があります

FAQのエントリ、多分?

記録のために、私たち(+ @ sbneto)はこれを少しの間推定に使用しており、非常にうまくやっています:

# monkeypatches.py

# Solving memory leak problem in pandas
# https://github.com/pandas-dev/pandas/issues/2659#issuecomment-12021083
import pandas as pd
from ctypes import cdll, CDLL
try:
    cdll.LoadLibrary("libc.so.6")
    libc = CDLL("libc.so.6")
    libc.malloc_trim(0)
except (OSError, AttributeError):
    libc = None

__old_del = getattr(pd.DataFrame, '__del__', None)

def __new_del(self):
    if __old_del:
        __old_del(self)
    libc.malloc_trim(0)

if libc:
    print('Applying monkeypatch for pd.DataFrame.__del__', file=sys.stderr)
    pd.DataFrame.__del__ = __new_del
else:
    print('Skipping monkeypatch for pd.DataFrame.__del__: libc or malloc_trim() not found', file=sys.stderr)

@alanjdsどうもありがとう!

しかし、他にも影響を受ける操作があります:-(

上記の問題(glibcの問題)に反応がないのは非常に奇妙です。 LinuxPCおよびサーバーのすべての環境に影響します。 そして...何も!!!

私は知っています、あなたは私に言うでしょう:わかりました、パッチを書いてください! 私がやります(UPD:しかし、glibcコードについて何も知らないので奇妙です)。 しかし、誰もそれを知りません。

誰もが言う:KDEがリークします。 誰が知っている-なぜ?! 誰も!

オープンソース? 恥ずかしい! 申し訳ありませんが、それはこの状況に当てはまります。

PS http://sourceware.org/bugzilla/show_bug.cgi?id=14827

私はあなたを信じています。 2年とその側の動きはありません:/

私はこちら側を修正し、そこでフォークすることは実行不可能に見えるので、非難の大きなコメントを置くと言います。

@alanjdsあなたのコードは、大きな頭痛の種を引き起こしていた私にとっての問題を修正しました。 デフォルトのパンダの動作とは何か、そしてコードがそれをどのように修正するかを説明していただけませんか?

デフォルトのアロケータとしてjemalloc切り替えることで、この問題を回避することもできます。 代わりのpython script.py 、実行LD_PRELOAD=/usr/lib/libjemalloc.so python script.pylibjemalloc.soへのパスはシステムによって異なる場合があり、最初にパッケージマネージャーでインストールする必要があることに注意してください。

@tchristensenowlet問題はglibcmallocコードにあるようです。 どうやら、そこでのfree実装は、 @ ghostのリンクでわかるように、特定のしきい値の後にmalloc_trimを発行する必要があるフラグを尊重していません。 したがって、 malloc_trimが呼び出されることはなく、メモリリークが発生します。 システムでライブラリが利用可能な場合は、手動でmalloc_trim呼び出すだけでした。 これを__del__()メソッドで呼び出します。これは、オブジェクトがガベージコレクションされたときに実行されます。

glibc.malloc.mxfast tunableがGlibc(https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Tunables.html)に導入されました。

これが私たちのプロジェクトの原因かもしれないと思いますが、ユーザーはデフォルトのPython 3.8(公式Webサイトから)でWindowsを実行しており、すべての依存関係はpipを介してインストールされています。 この問題はWindowsでも発生しますか? もしそうなら、 cdll.LoadLibrary("libc.so.6")相当は何でしょうか?

編集:ここで説明するこれらのテストを実行したところ、収集されたガベージは毎回適切に機能しました。
https://github.com/pandas-dev/pandas/issues/21353
システム:Windows 10
Python:3.8.5
パンダ:1.1.0

このページは役に立ちましたか?
1 / 5 - 1 評価