When adding and then removing many items from a PMap we are leaking memory somewhere.
Take the following script to reproduce:
import gc
from collections import Counter
from pyrsistent import pmap
# Create pmap, add 1M tems, then delete them.
m = pmap()
for i in range(1_000_000):
m = m.set(i, i)
for i in range(1_000_000):
m = m.discard(i)
# Now we have an empty map.
print(m)
# Print object counts.
gc.collect()
ct = Counter([type(o) for o in gc.get_objects()])
for k, v in sorted(ct.items(), key=lambda kv: kv[1])[-20:]:
print([k, v])
This produces:
pmap({})
[<class 'types.GenericAlias'>, 76]
[<class 're._constants._NamedIntConstant'>, 76]
[<class 'staticmethod'>, 86]
[<class '_frozen_importlib.ModuleSpec'>, 90]
[<class 'module'>, 92]
[<class 'classmethod'>, 93]
[<class 'frozenset'>, 105]
[<class 'set'>, 117]
[<class 'cell'>, 214]
[<class 'member_descriptor'>, 378]
[<class 'type'>, 403]
[<class 'getset_descriptor'>, 433]
[<class 'builtin_function_or_method'>, 793]
[<class 'method_descriptor'>, 806]
[<class 'weakref.ReferenceType'>, 836]
[<class 'wrapper_descriptor'>, 1124]
[<class 'dict'>, 1258]
[<class 'tuple'>, 1316]
[<class 'function'>, 2313]
[<class 'list'>, 34080]
For comparison, after removing the set/discard lines from the Python snippet, we have the following that remains:
pmap({})
[<class 'types.GenericAlias'>, 76]
[<class 're._constants._NamedIntConstant'>, 76]
[<class 'staticmethod'>, 86]
[<class '_frozen_importlib.ModuleSpec'>, 90]
[<class 'module'>, 92]
[<class 'classmethod'>, 93]
[<class 'frozenset'>, 105]
[<class 'set'>, 117]
[<class 'cell'>, 214]
[<class 'list'>, 254]
[<class 'member_descriptor'>, 378]
[<class 'type'>, 403]
[<class 'getset_descriptor'>, 433]
[<class 'builtin_function_or_method'>, 794]
[<class 'method_descriptor'>, 806]
[<class 'weakref.ReferenceType'>, 838]
[<class 'wrapper_descriptor'>, 1124]
[<class 'dict'>, 1258]
[<class 'tuple'>, 1342]
[<class 'function'>, 2313]
Looks like len(m._buckets) is still 1048576 after discarding all entries.
When adding and then removing many items from a
PMapwe are leaking memory somewhere.Take the following script to reproduce:
This produces:
For comparison, after removing the set/discard lines from the Python snippet, we have the following that remains:
Looks like
len(m._buckets)is still 1048576 after discarding all entries.