I'm fighting a memory leak in a Python project and spent much time on it already. I have deduced the problem to a small example. Now seems like I know the solution, but I can't understand why.
import random
def main():
d = {}
used_keys = []
n = 0
while True:
# choose a key unique enough among used previously
key = random.randint(0, 2 ** 60)
d[key] = 1234 # the value doesn't matter
used_keys.append(key)
n += 1
if n % 1000 == 0:
# clean up every 1000 iterations
print 'thousand'
for key in used_keys:
del d[key]
used_keys[:] = []
#used_keys = []
if __name__ == '__main__':
main()
The idea is that I store some values in the dict d
and memorize used keys in a list to be able to clean the dict from time to time.
This variation of the program confidently eats memory never returning it back. If I use alternative method to „clear” used_keys
that is commented in the example, all is fine: memory consumption stays at constant level.
Why?
Tested on CPython and many linuxes.
Second note, when no start is defined as in A[:2] , it defaults to 0. There are two ends to the list: the beginning where index=0 (the first element) and the end where index=highest value (the last element).
The short answer. Slicing lists does not generate copies of the objects in the list; it just copies the references to them. That is the answer to the question as asked.
One way to remember this is that the start point is inclusive and the end point is exclusive. In other words the slice will be from the start point up to but not including the end point. For the more visual folks another way is to to picture a wall before each value in the sequence.
Slice assignment is a little-used, beautiful Python feature to replace a slice with another sequence. Simply select the slice you want to replace on the left and the values to replace it on the right side of the equation.
Here's the reason - the current method does not delete the keys from the dict (only one, actually). This is because you clear the used_keys
list during the loop, and the loop exits prematurely.
The 2nd (commented) method, however, does work as you assign a new value to used_keys
so the loop finishes successfully.
See the difference between:
>>> a=[1,2,3]
>>> for x in a:
... print x
... a=[]
...
1
2
3
and
>>> a=[1,2,3]
>>> for x in a:
... print x
... a[:] = []
...
1
>>>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With