рдЬрд▓реНрдж рд╣реА рдЦрд╝рддреНрдо рд╣реЛрдиреЗ рд╡рд╛рд▓рд╛ рдПрдХ рд░рд╣рд╕реНрдп:
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()
рдареАрдХ рд╣реИ, рдпрд╣ рдПрдХ рд╢рдмреНрдж рдореЗрдВ, рдЪ * cked рд╣реИред рдЕрдЧрд░ рдореИрдВ рд▓реВрдк рдХреЗ рд▓рд┐рдП gc.collect рдЬреЛрдбрд╝рддрд╛ рд╣реВрдВ рддреЛ рдпрд╣ рдореЗрдореЛрд░реА рдХреЛ рд▓реАрдХ рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджреЗрддрд╛ рд╣реИ:
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()
рдпрд╣рд╛рдВ рдРрд╕реА рд╡рд╕реНрддреБрдПрдВ рд╣реИрдВ рдЬреЛ рдЪрдХреНрд░реАрдп рдЬреАрд╕реА рдЪрд▓рдиреЗ рдкрд░ рдХреЗрд╡рд▓ рдХрдЪрд░рд╛ рдПрдХрддреНрд░ рдХрд░рддреА рд╣реИрдВред рдпрд╣рд╛рдБ рдХреНрдпрд╛ рдЙрдкрд╛рдп рд╣реИ, __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()
рдореБрдЭреЗ рд╕рдВрджреЗрд╣ рд╣реИ рдХрд┐ рдЗрд╕рдХрд╛ рдЕрдЬрдЧрд░ рд╕реЗ рдХреЛрдИ рд▓реЗрдирд╛-рджреЗрдирд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЗрд╕рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░реЗрдЧрд╛ред
рд╣рд╛рдБ, рдпрд╣ рдЪрд╛рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рдЧ рд░рд╣рд╛ рдерд╛ред рд╕реНрдореГрддрд┐ рдЙрдкрдпреЛрдЧ 450MB рдХрд┐ IPython рдореЗрдВ рдЪрд▓рд╛рдиреЗ рдХреЗ рдмрд╛рдж, рддреЛ malloc_trim рдиреЗ 400MB рдХреЛ рдореБрдХреНрдд рдХрд░ рджрд┐рдпрд╛ред рдмрд╣реБрдд рдЕрд╢реБрдн
malloc_trim
рд▓реАрдб рдЕрдкрд╕реНрдЯреНрд░реАрдо рдХреЗ рдмрд╛рдж, рдпрд╣ рдПрдХ glibc рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬрд╝реЗрд╢рди рдХреА рддрд░рд╣ рд▓рдЧ рд░рд╣рд╛ рд╣реИред
xref:
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
рддрдм рдареАрдХ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдХрд┐рд╕реА рджрд┐рди рдкрдВрдбреЛрдВ рдХреЛ рдорд╛рд▓рдХрд┐рди рдЯреНрд░рд┐рдорд┐рдВрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдп рдХрд░рдиреЗ рдЪрд╛рд╣рд┐рдП
рдЕрдХреНрд╕рд░ рдкреВрдЫреЗ рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░рд╢реНрди рдореЗрдВ рдкреНрд░рд╡реЗрд╢, рд╢рд╛рдпрдж?
рд░рд┐рдХреЙрд░реНрдб рдХреЗ рд▓рд┐рдП, рд╣рдо (+ @ 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 рдХрд╛ рдореБрджреНрджрд╛) рдХреЛрдИ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдирд╣реАрдВ рд╣реИред рдпрд╣ рд▓рд┐рдирдХреНрд╕ рдкреАрд╕реА рдФрд░ рд╕рд░реНрд╡рд░ рдХреЗ рд╕рднреА рд╡рд╛рддрд╛рд╡рд░рдг рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИред рдФрд░ рдХреБрдЫ рдирд╣реАрдВ!!!
рдореБрдЭреЗ рдкрддрд╛ рд╣реИ, рдЖрдк рдореБрдЭреЗ рдХрд╣реЗрдВрдЧреЗ: рдареАрдХ рд╣реИ, рдПрдХ рдкреИрдЪ рд▓рд┐рдЦреЗрдВ! рдореИрдВ рдЗрд╕реЗ рдХрд░реВрдБрдЧрд╛ (UPD: рд▓реЗрдХрд┐рди рдпрд╣ рдЕрдЬреАрдм рдХрд╛рд░рдг рд╣реЛрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ рдореБрдЭреЗ glibc рдХреЛрдб рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рдирд╣реАрдВ рдкрддрд╛ рд╣реИ)ред рд▓реЗрдХрд┐рди рдпрд╣ рднреА рдХрд┐рд╕реА рдХреЛ рдкрддрд╛ рдирд╣реАрдВ рд╣реИред
рд╣рд░ рдХреЛрдИ рдХрд╣рддрд╛ рд╣реИ: рдХреЗрдбреАрдИ рд▓реАрдХред рдХреМрди рдЬрд╛рдирддрд╛ рд╣реИ - рдХреНрдпреЛрдВ ?! рдХреЛрдИ рднреА рдирд╣реАрдВ!
рдЦреБрд▓рд╛ рд╕реНрддреНрд░реЛрдд? рд╢рд░реНрдо рдХреА рдмрд╛рдд рд╣реИ! рдХреНрд╖рдорд╛ рдХрд░реЗрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рд╕рд╣реА рд╣реИред
рдореБрдЭреЗ рдЖрдк рдкрд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рд╣реИред 2 рд╕рд╛рд▓ рдФрд░ рдЙрд╕ рддрд░рдл рдХреЛрдИ рдХрджрдо рдирд╣реАрдВ: /
рдореИрдВ рдЗрд╕ рдкрдХреНрд╖ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рддрд╛ рд╣реВрдВ рдФрд░ рджреЛрд╖ рдХреА рдПрдХ рдмрдбрд╝реА рдЯрд┐рдкреНрдкрдгреА рдХрд░рддрд╛ рд╣реВрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╡рд╣рд╛рдВ рдлреЛрд░реНрдХрд┐рдВрдЧ рдЕрдХреНрд╖рдореНрдп рд▓рдЧрддреА рд╣реИред
@alanjds рдЖрдкрдХреЗ рдХреЛрдб рдиреЗ рдореЗрд░реЗ рд▓рд┐рдП рдПрдХ рд╕рдорд╕реНрдпрд╛ рддрдп рдХрд░ рджреА рд╣реИ рдЬреЛ рдПрдХ рдкреНрд░рдореБрдЦ рд╕рд┐рд░рджрд░реНрдж рдХрд╛ рдХрд╛рд░рдг рдмрди рд░рд╣реА рдереАред рдХреНрдпрд╛ рдЖрдк рдпрд╣ рдмрддрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВ рдХрд┐ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкрд╛рдВрдбрд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреНрдпрд╛ рд╣реИ рдФрд░ рдЖрдкрдХрд╛ рдХреЛрдб рдЗрд╕реЗ рдХреИрд╕реЗ рдареАрдХ рдХрд░рддрд╛ рд╣реИ?
рдЖрдк рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рдЕрдкрдиреЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдЖрд╡рдВрдЯрдирдХрд░реНрддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ jemalloc
рд╕реНрд╡рд┐рдЪ рдХрд░рдХреЗ рднреА рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдХреЗ рдмрдЬрд╛рдп python script.py
, рдЪрд▓рд╛рдиреЗ LD_PRELOAD=/usr/lib/libjemalloc.so python script.py
ред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ libjemalloc.so
рдХрд╛ рдкрде рдЖрдкрдХреЗ рд╕рд┐рд╕реНрдЯрдо рдкрд░ рднрд┐рдиреНрди рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рдЗрд╕реЗ рдЕрдкрдиреЗ рдкреИрдХреЗрдЬ рдореИрдиреЗрдЬрд░ рдХреЗ рд╕рд╛рде рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
@tchristensenowlet рд╕рдорд╕реНрдпрд╛ malloc
glibc
рдХреЛрдб рдореЗрдВ рд▓рдЧрддреА рд╣реИред рдЬрд╛рд╣рд┐рд░рд╛ рддреМрд░ рдкрд░, free
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд╣рд╛рдБ рдПрдХ рдзреНрд╡рдЬ рдХрд╛ рд╕рдореНрдорд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕реАрдорд╛ рдХреЗ рдмрд╛рдж malloc_trim
рдЬрд╛рд░реА рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк @ghost рдХреЗ рд▓рд┐рдВрдХ рдореЗрдВ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, malloc_trim
рдХреЛ рдХрднреА рднреА рдореЗрдореЛрд░реА рд▓реАрдХ рдирд╣реАрдВ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рд╣рдордиреЗ рдЬреЛ рдХрд┐рдпрд╛ рд╡рд╣ рдмрд╕ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ malloc_trim
рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ, рдпрджрд┐ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИред рд╣рдо рдЗрд╕реЗ __del__()
рд╡рд┐рдзрд┐ рдореЗрдВ рдХрд╣рддреЗ рд╣реИрдВ, рдЬрд┐рд╕реЗ рддрдм рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рдСрдмреНрдЬреЗрдХреНрдЯ рдХрдЪрд░рд╛ рдПрдХрддреНрд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
glibc.malloc.mxfast
tunable рдХреЛ Glibc (https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Tunables.html) рдореЗрдВ рдкреЗрд╢ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рд╕реЗ рдПрдХ рдореЗрдВ рдЕрдкрд░рд╛рдзреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкрд╛рдпрдерди 3.8 (рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рд╡реЗрдмрд╕рд╛рдЗрдЯ рд╕реЗ) рдФрд░ рдкрд╛рдЗрдк рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рд╕рднреА рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рд╕рд╛рде рд╡рд┐рдВрдбреЛрдЬ рдЪрд▓рд╛ рд░рд╣реЗ рд╣реИрдВред рдХреНрдпрд╛ рдпрд╣ рд╕рдорд╕реНрдпрд╛ рд╡рд┐рдВрдбреЛрдЬ рдкрд░ рднреА рд╣реЛрдЧреА? рдпрджрд┐ рд╣рд╛рдВ, рддреЛ cdll.LoadLibrary("libc.so.6")
рд╕рдорддреБрд▓реНрдп рдХреНрдпрд╛ рд╣реЛрдЧрд╛?
рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдореИрдВрдиреЗ рдпрд╣рд╛рдВ рд╡рд░реНрдгрд┐рдд рдЗрди рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЛ рдЪрд▓рд╛рдпрд╛, рдФрд░ рдПрдХрддреНрд░ рдХрд┐рдП рдЧрдП рдХрдЪрд░реЗ рдиреЗ рд╣рд░ рдмрд╛рд░ рдЕрдкрдирд╛ рдХрд╛рдо рдареАрдХ рд╕реЗ рдХрд┐рдпрд╛:
https://github.com/pandas-dev/pandas/issues/21353
рд╕рд┐рд╕реНрдЯрдо: рд╡рд┐рдВрдбреЛрдЬ 10
рдкрд╛рдпрдерди: 3.8.5
рдкрдВрдбреЛрдВ: 1.1.0
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рд░рд┐рдХреЙрд░реНрдб рдХреЗ рд▓рд┐рдП, рд╣рдо (+ @ sbneto) рдереЛрдбрд╝реЗ рд╕рдордп рдХреЗ рд▓рд┐рдП рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдФрд░ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ: