[PyQt] Possible memory leak with signal connections

Kevin Keating kevin.keating at schrodinger.com
Wed Sep 25 22:05:43 BST 2019


On 9/25/2019 9:17:24 AM, Phil Thompson <phil at riverbankcomputing.com> wrote:
On 19/09/2019 19:53, Kevin Keating wrote:
> I've found what appears to be a memory leak caused by connecting
> signals to slots that lack a QtCore.pyqtSlot decorator.  I know that
> connections without the pyqtSlot decorator are expected to use more
> memory than connections with the decorator based on
> https://www.codeproject.com/Articles/1123088/PyQt-signal-slot-connection-performance. 
> In the script I've pasted below, though, connections without the
> pyqtSlot decorator continue to consume memory even after the signal
> has been disconnected and the QObjects have been discarded.  The
> script does the following:
>   - Instantiates a bunch of SignalObjects, which are QObjects with a
> signal, and stores the SingalObjects in a list.
>   - Instantiates a bunch of SlotObjects, which are QObjects with
> slots.  Each SlotObject slot is connected to the signals from all the
> SignalObjects.  The SlotObjects are then immediately discarded.
>   - Discards all SignalObjects.
>   - Runs gc.collect()
>   - Runs the QApplication's event loop for a second in case there are
> any pending DeferredDelete events.
>
> If the SlotObject class uses the QtCore.pyqtSlot decorator, then
> memory usage at the end of the script is the same as what it was at
> the beginning of the script, which makes sense since all the objects
> that get created should be completely destroyed before the script
> finishes.  Here's the output that I get with pyqtSlot decorators:
>         Memory before signal_objects creation: 17.1MiB
>         Memory before slot objects creation: 17.1MiB
>                 Difference: 0.0B
>         Memory after slot objects creation: 17.1MiB
>                 Difference: 0.0B
>         Memory after event loop runs: 17.1MiB
>                 Difference: 0.0B
> If the SlotObject class doesn't use the QtCore.pyqtSlot decorator,
> though, then memory usage at the end of the script is substantially
> higher.  Here's the output that I get without pyqtSlot decorators:
>         Memory before signal_objects creation: 17.0MiB
>         Memory before slot objects creation: 17.0MiB
>                 Difference: 0.0B
>         Memory after slot objects creation: 210.6MiB
>                 Difference: 193.5MiB
>         Memory after event loop runs: 210.6MiB
>                 Difference: 193.5MiB
> Is this expected behavior?  Without pyqtSlot decorators, is there
> anything I can do to recover the 193 MiB of memory other than
> terminating the process?  Thanks!
>
> I've tested the script with Python 3.6.2, PyQt 5.12.2, and Qt 5.12.3
> on Windows 10, Linux, and Mac OS.  I've also tested with Python 3.6.5,
> PyQt 5.13.1, and Qt 5.13.1 on Windows 10.  All of them give similar
> results.  The script requires the psutil package
> (https://pypi.org/project/psutil/) to monitor memory usage.

Are you expecting that the Python interpreter will return unused memory
to the operating system?

Phil

My assumption was that the memory usage from the signal connections wouldn't "build up" (i.e. that memory usage would be independent of the number of SignalObjects instantiated), which seems to be what happens with the pyqtSlot decorated version.  In create_slot_objects, each SlotObject is instantiated, which connects the signals, and then should be immediately garbage collected, which should disconnect the signals.  In the version of the script without the pyqtSlot decorators, the number reported for "Memory after slot objects creation" is proportional to the number of SlotObject instances created, which is why I'd assumed memory had leaked, but I could certainly be thinking through things wrong.

- Kevin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190925/40d4a04c/attachment.html>


More information about the PyQt mailing list