--- author: '' category: '' date: 2012/02/10 22:57 description: '' link: '' priority: '' slug: BB990 tags: pyqt, python, qt title: 'PyQt Quickie: Don''t Get Garbage Collected' type: text updated: 2012/02/10 22:57 url_type: '' --- There is one area where Qt and Python (and in consequence PyQt) have major disagreements. That area is memory management. While Qt has its own mechanisms to handle object allocation and disposal (the hierarchical QObject trees, smart pointers, etc.), PyQt runs on Python, so it has garbage collection. Let's consider a simple example: .. code-block:: python from PyQt4 import QtCore def finished(): print "The process is done!" # Quit the app QtCore.QCoreApplication.instance().quit() def launch_process(): # Do something asynchronously proc = QtCore.QProcess() proc.start("/bin/sleep 3") # After it finishes, call finished proc.finished.connect(finished) def main(): app = QtCore.QCoreApplication([]) # Launch the process launch_process() app.exec_() main() If you run this, this is what will happen:: QProcess: Destroyed while process is still running. The process is done! Plus, the script never ends. Fun! The problem is that ``proc`` is being deleted at the end of ``launch_process`` because there are no more references to it. Here is a better way to do it: .. code-block:: python from PyQt4 import QtCore processes = set([]) def finished(): print "The process is done!" # Quit the app QtCore.QCoreApplication.instance().quit() def launch_process(): # Do something asynchronously proc = QtCore.QProcess() processes.add(proc) proc.start("/bin/sleep 3") # After it finishes, call finished proc.finished.connect(finished) def main(): app = QtCore.QCoreApplication([]) # Launch the process launch_process() app.exec_() main() Here, we add a global ``processes`` set and add ``proc`` there so we always keep a reference to it. Now, the program works as intended. However, it still has an issue: we are leaking ``QProcess`` objects. While in this case the leak is very short-lived, since we are ending the program right after the process ends, in a real program this is not a good idea. So, we would need to add a way to remove ``proc`` from ``processes`` in ``finished``. This is not as easy as it may seem. Here is an idea that will not work as you expect: .. code-block:: python def launch_process(): # Do something asynchronously proc = QtCore.QProcess() processes.add(proc) proc.start("/bin/sleep 3") # Remove the process from the global set when done proc.finished.connect(lambda: processes.remove(proc)) # After it finishes, call finished proc.finished.connect(finished) In this version, we will still leak ``proc``, even though ``processes`` is empty! Why? Because we are keeping a reference to ``proc`` in the ``lambda``! I don't really have a good answer for that that doesn't involve turning everything into members of a ``QObject`` and using ``sender`` to figure out what process is ending, or using ``QSignalMapper``. That version is left as an exercise.