Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak with %matplotlib qt, with simple fix #14240

Closed
pag opened this issue Nov 11, 2023 · 4 comments · Fixed by #14251
Closed

Memory leak with %matplotlib qt, with simple fix #14240

pag opened this issue Nov 11, 2023 · 4 comments · Fixed by #14251
Labels
Milestone

Comments

@pag
Copy link

pag commented Nov 11, 2023

When using matplotlib event loop integration (e.g. %matplotlib) with pyqt, there is a memory leak caused by a misunderstanding of the lifespan of QObjects.

I found it because I'm trying to debug slowdowns in long-running IPython sessions with autoreload. I'm not sure that this is actually the cause, but it's certainly ugly. Within a session which has been open for a couple of weeks I found:

>>> collections.Counter(map(type, gc.get_objects())).most_common(5)
[(PyQt5.QtCore.QEventLoop, 1718061),
 (dict, 1006864),
 (list, 702602),
 (ast.Name, 267460),
 (ast.Attribute, 96929)]

There are 1.7m QEventLoop instances kicking around. They are being created by IPython.terminal.pt_inputhooks.qt.inputhook on line 58, with event_loop = QtCore.QEventLoop(app). But QEventLoop is a QObject subclass, which means that passing app in the constructor parents the instance to app, so even when it exits the scope it won't be deleted, even though it's no longer needed by that point.

The fix is simple: just add a line at the end of that function containing event_loop.setParent(None).

Hopefully it's faster for you to just add that single line of code rather than me forking, making a pull request etc, but please tell me if you need me to do so.

@ccordoba12 ccordoba12 added the bug label Nov 13, 2023
@ccordoba12
Copy link
Member

The fix is simple: just add a line at the end of that function containing event_loop.setParent(None).

Thanks for finding a fix @pag!

Hopefully it's faster for you to just add that single line of code rather than me forking, making a pull request etc, but please tell me if you need me to do so.

Unfortunately, it's not because we're busy with other things. So, please submit a pull request to fix this issue.

hperrey added a commit to hperrey/ipython that referenced this issue Nov 23, 2023
See: ipython#14240

- the QEventLoop, `event_loop`, is not deleted when exiting the scope as
passing `app` to the constructor parents the object to `app`. This
creates a memory leak as QEventLoop objects are being accumulated.
- issue reported by and fix suggested by @pag
@hperrey
Copy link
Contributor

hperrey commented Nov 23, 2023

Thanks @pag for the suggested fix! We just discovered a memory leak on our machines related to IPython and this issue helped a lot to track down the problem!

I took the liberty of creating a PR, citing you.

@pag
Copy link
Author

pag commented Nov 23, 2023

Thanks for that @hperrey.

The other memory leak I found was related to those ast objects you can see in the count, basically vast numbers of objects are created and kept alive till the end of the session each time that an exception is raised with 'xmode Verbose'. They're being kept alive in the stack_data module. Swapping to simpler tracebacks with e.g. xmode Context fixes that. With that done and the Qt fix above, long-running sessions use constant space and autoreload doesn't slow down!

@hperrey
Copy link
Contributor

hperrey commented Nov 23, 2023

@pag, interesting, I had not noted that but will keep an eye out for that source of leaks!

@ccordoba12 ccordoba12 added this to the 8.18 milestone Nov 24, 2023
Carreau added a commit that referenced this issue Nov 24, 2023
The QEventLoop object, `event_loop`, created in
`IPython/terminal/pt_intputhooks/qt.py` L58 is not deleted when exiting
the scope as passing `app` to the constructor parents the object to
`app`. This creates a memory leak as QEventLoop objects are being
accumulated.

The issue was originally reported by @pag who also suggested the fix.

`pytest IPython/terminal/tests/` runs through without errors. I have
tested the changes and see no more accumulation of `QEventLoop` objects.

This fixes #14240
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants