I do not think that the problem is related to exec - the garbage collector simply does not activate. If you extract exec'd code into the main application, both methods give the same behavior as with exec :
class test: def __init__(self): self.buf = '1'*1024*1024*200 x = test()
The differences between the two methods are that in the second case, the local area changes when f1() called, and I think the garbage collector lights up when x goes out of scope because the function returns control to return to the main script. If the scope does not change, the garbage collector waits until the difference between the number of distributions and the number of deallocations exceeds its threshold value (on my machine, the default threshold of 700 is to start Python 2.7).
We can understand a little what is happening:
import sys import gc class test: def __init__(self): self.buf = '1'*1024*1024*200 x = test() print gc.get_count()
So we see that the garbage collector fires many times, but for some reason does not collect x . If you check with a different version:
import sys import gc class test: def __init__(self): self.buf = '1'*1024*1024*200 def f1(): x = test() f1() print gc.get_count()
In this case, we know that he managed to collect x . Thus, it seems that when x declared in the global scope, it retains some circular reference to itself, which prevents its collection. We can always use del x for manual forced collection, but of course, this is not ideal. If you use gc.get_referrers(x) , we can see which objects are still related to x , and perhaps this will make it clear how to stop this.
I know that I really did not solve the problem, but I hope this helped you in the right direction. I will remember this problem if I find something later.
source share