You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The following script exhibits the memory leak. It only happens if "dispatch_table" is set _before_ calling super().__init__, which is pretty unexpected.
importpickleimportioimportgcimporttracemalloctracemalloc.start(10)
snap=tracemalloc.take_snapshot()
classMyPickler(pickle.Pickler):
def__init__(self, *args, **kwargs):
# Swapping the next 2 lines "solves" the memory leak for some reasonself.dispatch_table=dict()
super().__init__(*args, **kwargs)
l=[]
foriinrange(10000):
ifi%1000==0:
print('='*80)
snap2=tracemalloc.take_snapshot()
stats=snap2.compare_to(snap, 'lineno')
forsinstats[:10]:
print(s)
snap=snap2f=io.BytesIO()
MyPickler(f)
gc.collect()
The output of the last iteration is as follow. The leak of 562 kiB is apparent:
testmem.py:12: size=562 KiB (+62.5 KiB), count=9000 (+1000), average=64 B
/usr/lib/python3.10/tracemalloc.py:125: size=2376 B (-72 B), count=33 (-1), average=72 B
/usr/lib/python3.10/tracemalloc.py:129: size=72 B (+72 B), count=1 (+1), average=72 B
/usr/lib/python3.10/tracemalloc.py:502: size=252 B (+28 B), count=9 (+1), average=28 B
/usr/lib/python3.10/tracemalloc.py:498: size=2104 B (+0 B), count=36 (+0), average=58 B
/home/dourai01/Work/lisa/lisa/testmem.py:10: size=1844 B (+0 B), count=9 (+0), average=205 B
/usr/lib/python3.10/tracemalloc.py:193: size=1680 B (+0 B), count=35 (+0), average=48 B
/usr/lib/python3.10/tracemalloc.py:547: size=1256 B (+0 B), count=3 (+0), average=419 B
/usr/lib/python3.10/tracemalloc.py:226: size=832 B (+0 B), count=2 (+0), average=416 B
/usr/lib/python3.10/tracemalloc.py:173: size=800 B (+0 B), count=2 (+0), average=400 B
If "dispatch_table" is set after calling super().__init__, there is no leak anymore:
/usr/lib/python3.10/tracemalloc.py:135: size=740 B (+740 B), count=7 (+7), average=106 B
/usr/lib/python3.10/tracemalloc.py:125: size=2088 B (-656 B), count=29 (-4), average=72 B
/usr/lib/python3.10/tracemalloc.py:136: size=320 B (+320 B), count=1 (+1), average=320 B
/usr/lib/python3.10/tracemalloc.py:132: size=0 B (-256 B), count=0 (-1)
/usr/lib/python3.10/tracemalloc.py:129: size=72 B (+72 B), count=1 (+1), average=72 B
/usr/lib/python3.10/tracemalloc.py:498: size=2008 B (+48 B), count=34 (+1), average=59 B
/usr/lib/python3.10/tracemalloc.py:193: size=1584 B (+48 B), count=33 (+1), average=48 B
/usr/lib/python3.10/tracemalloc.py:502: size=196 B (-28 B), count=7 (-1), average=28 B
/usr/lib/python3.10/tracemalloc.py:126: size=84 B (+28 B), count=3 (+1), average=28 B
Activity
douglas-raillard-arm commentedon Nov 17, 2021
The following script exhibits the memory leak. It only happens if "dispatch_table" is set _before_ calling super().__init__, which is pretty unexpected.
The output of the last iteration is as follow. The leak of 562 kiB is apparent:
If "dispatch_table" is set after calling super().__init__, there is no leak anymore:
tigerinus commentedon Jun 3, 2022
I can verify this also happens on Python 3.9.2
I also have a demonstration of this memory leak at https://github.com/tigerinus/pickle_memory_leak_with_msgspec
tigerinus commentedon Jun 4, 2022
The issue I found turns out to be an issue of msgspec.Struct and should be fixed by msgspec/msgspec#117
GH-89988: Fix memory leak in pickle.Pickler dispatch_table lookup (GH…
pythonGH-89988: Fix memory leak in pickle.Pickler dispatch_table look…
pythonGH-89988: Fix memory leak in pickle.Pickler dispatch_table look…
[3.10] GH-89988: Fix memory leak in pickle.Pickler dispatch_table loo…
pythonGH-89988: Fix memory leak in pickle.Pickler dispatch_table look…
GH-89988: Fix memory leak in pickle.Pickler dispatch_table lookup (GH…