Do Python dictionaries have all memory freed when reassigned? - python

Working in Python. I have a function that reads from a queue and creates a dictionary based on some of the XML tags in the record read from the queue, and returns this dictionary. I call this function in a loop forever. The dictionary gets reassigned each time. Does the memory previously used by the dictionary get freed at each reassignment, or does it get orphaned and eventually cause memory problems?
def readq():
qtags = {}
# Omitted code to read the queue record, get XML string, DOMify it
qtags['result'] = "Success"
qtags['call_offer_time'] = get_node_value_by_name(audio_dom, 'call_offer_time')
# More omitted code to extract the rest of the tags
return qtags
while signals.sigterm_caught == False:
tags = readq()
if tags['result'] == "Empty":
time.sleep(SLEEP_TIME)
continue
# Do stuff with the tags
So when I reassign tags each time in that loop, will the memory used by the previous assignment get freed before being allocated by the new assignment?

The memory of an object will be freed if it can be proven (from the knowledge the language implementation has at runtime) that it cannot possibly be accessed any more and the garbage collector sees it fit to make a collection. That's the absolute minimum, and you shouldn't assume any more. And you usually shouldn't have to worry about anything more.
More practically speaking, it may be freed at some point in time between the last reference (where "reference" isn't limited to names in scope, but can be anything that makes the object reachable) being removed and memory running out. It doesn't have to be freed by the Python implementation running your code, it may as well leave the memory cleaning to the OS and forget about any finalizers and such. Note that there can be a noticeable delay between the last reference dying and memory usage actually dropping. But as mentioned before, most implementations go out of their way to avoid excessive memory usage if there is garbage to collect.
Even more practically, you'll propably be running this on CPython (the reference implementation), which always used and most propably will always use reference counting (augmented with a real GC to handle cyclic references), so unless there's a cyclic reference (relatively rare and your code doesn't look like it has them, but can occur e.g. in graph-like structures) it will be freed as soon as the last reference to it is deleted/overwritten. Of course, other implementations aren't that predictable - PyPy alone has half a dozen different garbage collectors, all but one falling under the above paragraph.

No, it will be freed AFTER the new object has been created.
In order for the reference count to go down on the old object, tags has to be pointed to the new object. This happens after readq returns, so at the very least both objects will exist from the beginning of qtags = {} to after tags = readq().
As #delnan stated, soon after tags has been pointed to the new object, the old one will be freed by the garbage collector as there is no longer a reference to it.

Usually Python can keep up with anything you throw at it. The Garbage collector used in Python uses reference counting, so your memory usage should be about constant, you won't see any spikes in memory. Right when you remove a reference (assign the variable to something else), the garbage collector throws the memory back into the "heap" if you will. So don't worry about memory. I have run simulators doing tests for hours rewriting variables, but the memory usage stays about the same. It will be freed when you assign it a new dictionary.

Related

Freeing up all used memory in python

Setup:
I am running a python code where:
I open a file.
For every line in file, I create an object
Do some operations with the object
Note that once I am done with the operations part, I no longer need the object. Every new line is independent.
Relevant Code as per request:
I have commented all the parts of my code, leaving below the following code:
import gc
for l in range(num_lines):
inp = f.readline()[:-1]
collector = [int(i) for i in inp]
M = BooleanFunction(collector)
deg = M.algebraic_degree()
del M
gc.collect()
The problem:
The object once created, is consuming some amount of memory. After performing the operations, I am not able to free it. So while looping over the file, my memory keeps getting accumulated with new objects, and by around 793 lines into the file, my 16 GB of RAM is completely depleted.
What I have tried:
Using the garbage collector:
import gc
del Object
gc.collect()
However, the garbage collector will not free up the RAM (or) python is not giving up the memory to the system. Creating child-processes is an idea, but not what I am up for.
Questions:
Is there any way I can free up all the memory currently occupied by the program to the OS? That means removing all variables (loop vars, global vars, etc). Something similar to what happens when you press CTRL+C to terminate the program, it returns all the memory to the OS.
A way to specifically de-allocate an object (If I am not doing it right).
Previous questions do not answer what if gc.collect() fails to do so and how do I completely give up the memory allocated.
Objects in Python can be garbage-colleted once their reference count drops to zero.
Looking at your code, every variable gets re-assigned in every iteration. So their reference count should be zero.
If that doesn't happen then I can see three main possibilities;
You are unwittingly keeping a reference to that object.
Garbage collection is disabled (gc.disable()) or frozen (gc.freeze() in Python 3.7).
The objects are made by a Python extension written in C that manages its own memory.
Note that (1) or (2) doesn't have to happen in your code. It can also happen in modules that you use.
In your case (2) should not be an issue since you force garbage collection.
For an example of (1), consider what would happen if BooleanFunction was memoized. Then a reference to each object (that you wouldn't see and can't delete) would be kept.
The only way to give all memory back to the OS is to terminate the program.
Edit 1:
Try running your program with the garbage collection debug flags enabled (gc.DEBUG_LEAK). Run gc.get_count() at the end of every loop. And maybe gc.garbage() as well.
For a better understanding of where the memory allocation happens and what exactly happens, you could run your script under the Python debugger. Step through the program line by line while monitoring the resident set size of the Python process with ps in another terminal.

how to deallocate heap memory in python

I am coming from C++ where I worked on heap memory and there I had to delete the memory of heap which I created on heap using 'new' keyword and I am always in confusion what to do in python for heap memory to stop memory leakage please recommend me any text for detail of python memory allocation and deletion.Thanks
You do not have to do anything: Python first of all uses reference counting. This means that for every object it holds a counter that is incremented when you reference that object through a new variable, and decrements the counter in case you let the variable point to something else. In case the counter hits zero, then the object will be deleted (or scheduled for deletion).
This is not enough however, since two objects can reference each other and thus even if no other variable refer to the objects, these objects keep each other alive. For that, Python has an (optional) garbage collector that does cycle detection. In case such cycles are found, the objects are deleted. You can schedule such collection by calling gc.collect().
In short: Python takes care of memory management itself. Of course it is your task to make sure objects can be released. For instance it is wise not to refer to a large object longer than necessary. You can do this for instance by using the del keyword:
foo = ... # some large object
# ...
# use foo for some tasks
del foo
# ...
# do some other tasks
by using del we have removed the foo variable, and thus we also decremented the counter refering to the object to which foo was refering. As a result, the object foo was refering too can be scheduled for removal (earlier). Of course compilers/interpreters can do liveness analysis, and perhaps find out themselves that you do not use foo anymore, but better be safe than sorry.
So in short: Python manages memory itself by using reference counting and a garbage collector, the thing you have to worry about is that not that much objects are still "alive" if these are no longer necessary.
Python is a high level language. And here you need not worry about memory de-allocation. It is the responsibility of the python runtime to manage memory allocations and de-allocations.

Python - Garbage collector for list

I made simple loop which for each iteration, appends a number to a list.
After the program has completed, will the memory used by the list be automatically freed?
if __name__ == '__main__':
for i in range(100000):
list.append(i)
Anyone can explain to me please?
Yes, all memory is freed when the program is terminated. There is just no way in a modern operating system for you to reserve memory and not have it freed when the process is terminated.
Garbage collector is for freeing memory before the program terminates. This way long-running programs won't reserved all the resources of the computer.
If you have a big data structure, and you want the garbage collector to take care of it (free the memory used by it), you should remove all references to it after you're done using it. In this case simple del list would be sufficient.
Yes, the operating system takes care and frees the memory used by a process after it terminates. Python has nothing to do with it.
However, Python itself has automatic garbage collection, so it frees all of the memory that is no longer necessary while your Python program is running.
Finally, you probably should just use:
if __name__ == '__main__':
list = range(100000)
to achieve exactly the same thing you have written.
Yes, the memory will be freed when the program terminates and on most implementations it will also be freed when the reference count to that list reaches zero, i.e., when there is no variables in scope pointing to that value.
You can also manually control the GC using the gc module.
If you are just iterating over the list and the list is big enough to get you worried about memory consumption, you probably should check Python generators and generator expressions.
So instead of:
for i in range(100000):
results.append(do_something_with(i))
for result in results:
do_something_else_with(result)
You can write:
partial = (do_something_with(i) for i in range(100000))
for result in partial:
do_something_else_with(result)
Or:
def do_something(iterable):
for item in iterable:
yield some_calculation(item)
def do_something_else(iterable):
for item in iterable:
yield some_other_calculation(item)
partial = do_something(range(100000))
for result in do_something_else(partial):
print result
And so on... This way you don't have to allocate the whole list in memory.
You needn't worry about freeing memory in python, since this is an automatic feature of the program. Python uses reference counting to manage memory, when something is no longer being referenced, python will automatically allocate memory accordingly. In other words, removing all references to the list should be enough to free the memory that was allocated to it.
That said, if your program is huge, you may use gc.collect() to make the garbage collector free some memory. However, this is generally unnecessary, as Python's garbage collector is designed to do its job well enough.
Moreover, although this is not recommended, and generally never very useful, you may also disable Python's automatic garbage collector using gc.disable(), which allows you as the user to allocate the memory manually, in an almost C style approach.
All the memory will be freed after termination but if you want to be efficient in creating a list this large during execution use xrange instead which generates the number on the fly.
alist = [i for i in xrange(10000)]

Is there a need to delete a large variable in python immediately after its use?

If I create a list that’s 1 GB, print it to screen, then delete it, would it also be deleted from memory? Would this deletion essentially be like deallocating memory such as free() in C.
If a variable is very large should I delete it immediately after use or should I let Python's garbage collector handle it ?
# E.g. creating and deleting a large list
largeList = ['data', 'etc', 'etc'] # Continues to 1 GB
print largeList
largeList = [] # Or would it need to be: del largeList [:]
Most of the time, you shouldn't worry about memory management in a garbage collected language. That means actions such as deleting variables (in python), or calling the garbage collector (GC) manually.
You should trust the GC to do its job properly - most of the time, micromanaging memory will lead to adverse results, as the GC has a lot more information and statistics about what memory is used and needed than you. Also, garbage collection is a expensive process (CPU-wise), so there's a good chance you'd be calling it too often/in a bad moment.
What happens in your example is that, as soon as ỳou largeList = [], the memory content previously referenced will be GC'd as soon as its convenient, or the memory is needed.
You can check this using a interpreter and a memory monitor:
#5 MiB used
>>> l1=[0]*1024*1024*32
#261 MiB used
>>> l2=[0]*1024*1024*32
#525 MiB used
>>> l1=[0]*1024*1024*32
# 525 MiB used
There are very rare cases where you do need to manage memory manually, and you turn off garbage collection. Of course, that can lead to memory leak bugs such as this one. It's worth mentioning that the modern python GC can handle circular references properly.
Using "die" ---> Deletion of a name removes the binding of that name from the local or global namespace. It releases memory for sure but not all the memory is released.
NOTE: When a process frees some memory from HEAP, it releases back to the OS only after the process dies.
So, better leave it for the Garbage Collector.

Why is the destructor called when the CPython garbage collector is disabled?

I'm trying to understand the internals of the CPython garbage collector, specifically when the destructor is called. So far, the behavior is intuitive, but the following case trips me up:
Disable the GC.
Create an object, then remove a reference to it.
The object is destroyed and the _____del_____ method is called.
I thought this would only happen if the garbage collector was enabled. Can someone explain why this happens? Is there a way to defer calling the destructor?
import gc
import unittest
_destroyed = False
class MyClass(object):
def __del__(self):
global _destroyed
_destroyed = True
class GarbageCollectionTest(unittest.TestCase):
def testExplicitGarbageCollection(self):
gc.disable()
ref = MyClass()
ref = None
# The next test fails.
# The object is automatically destroyed even with the collector turned off.
self.assertFalse(_destroyed)
gc.collect()
self.assertTrue(_destroyed)
if __name__=='__main__':
unittest.main()
Disclaimer: this code is not meant for production -- I've already noted that this is very implementation-specific and does not work on Jython.
Python has both reference counting garbage collection and cyclic garbage collection, and it's the latter that the gc module controls. Reference counting can't be disabled, and hence still happens when the cyclic garbage collector is switched off.
Since there are no references left to your object after ref = None, its __del__ method is called as a result of its reference count going to zero.
There's a clue in the documentation: "Since the collector supplements the reference counting already used in Python..." (my emphasis).
You can stop the first assertion from firing by making the object refer to itself, so that its reference count doesn't go to zero, for instance by giving it this constructor:
def __init__(self):
self.myself = self
But if you do that, the second assertion will fire. That's because garbage cycles with __del__ methods don't get collected - see the documentation for gc.garbage.
The docs here (original link was to a documentation section which up to Python 3.5 was here, and was later relocated) explain how what's called "the optional garbage collector" is actually a collector of cyclic garbage (the kind that reference counting wouldn't catch) (see also here). Reference counting is explained here, with a nod to its interplay with the cyclic gc:
While Python uses the traditional
reference counting implementation, it
also offers a cycle detector that
works to detect reference cycles. This
allows applications to not worry about
creating direct or indirect circular
references; these are the weakness of
garbage collection implemented using
only reference counting. Reference
cycles consist of objects which
contain (possibly indirect) references
to themselves, so that each object in
the cycle has a reference count which
is non-zero. Typical reference
counting implementations are not able
to reclaim the memory belonging to any
objects in a reference cycle, or
referenced from the objects in the
cycle, even though there are no
further references to the cycle
itself.
Depending on your definition of garbage collector, CPython has two garbage collectors, the reference counting one, and the other one.
The reference counter is always working, and cannot be turned off, as it's quite a fast and lightweight one that does not sigificantly affect the run time of the system.
The other one (some varient of mark and sweep, I think), gets run every so often, and can be disabled. This is because it requires the interpreter to be paused while it is running, and this can happen at the wrong moment, and consume quite a lot of CPU time.
This ability to disable it is there for those time when you expect to be doing something that's time critical, and the lack of this GC won't cause you any problems.

Categories