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

Fix image memory issues #1109

Merged
merged 2 commits into from
Feb 24, 2022
Merged

Fix image memory issues #1109

merged 2 commits into from
Feb 24, 2022

Conversation

corranwebster
Copy link
Contributor

@corranwebster corranwebster commented Feb 23, 2022

Fixes #1108 (hopefully).

This stashes a back-reference to a QImage when it is used to create a QPixmap to ensure that the QImage isn't gc-d until we're done with it.

The example from TraitsUI looks like this after the fix:
image

Unfortunately I don't see a way to create a regression test.

For a reviewer - to replicate set up a Windows/Python3.6/Pyside2 environment with the main branch of TraitsUI and the main branch of Pyface - you should see corruption or get a segfault. Switching to this branch should fix the problem.

@jwiggins
Copy link
Member

How is the QImage being created? Is it using the same strategy to keep a reference to its backing buffer? See https://github.com/python-pillow/Pillow/blob/7.2.x/src/PIL/ImageQt.py#L166-L170

@corranwebster
Copy link
Contributor Author

corranwebster commented Feb 24, 2022

How is the QImage being created? Is it using the same strategy to keep a reference to its backing buffer?

For arrays we stash a reference to (a shuffled copy) of the array here:

image._numpy_data = data

For a PIL ImageQt the original Image instance is stored in a trait on the PILImage class:

image = Instance("PIL.Image.Image")

Edit: plus it looks like PIL is also stashing a reference.

@@ -45,7 +45,9 @@ def image_to_bitmap(image):
bitmap : QPixmap
The corresponding QPixmap.
"""
return QPixmap.fromImage(image)
bitmap = QPixmap.fromImage(image)
bitmap._image = image
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest adding a comment explaining why this is necessary.

@jwiggins
Copy link
Member

If this code is only consuming QImage instances that are also created by pyface and have a ref to their underlying buffer, perhaps having the QPixmap reference the buffer would avoid keeping a QImage around unnecessarily?

I'm speculating a little, so don't take this too seriously. I'm 👍 on the proposed solution but only wonder if perhaps the QImage object is made redundant here.

Copy link
Member

@mdickinson mdickinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but a comment explaining why this code is doing what it's doing would be useful.

@corranwebster
Copy link
Contributor Author

corranwebster commented Feb 24, 2022

If this code is only consuming QImage instances that are also created by pyface and have a ref to their underlying buffer, perhaps having the QPixmap reference the buffer would avoid keeping a QImage around unnecessarily?

There's no way I know of to create a QPixmap directly from a numpy array - it can be created from various file formats directly, but not an array of RGB(A) as far as I can see - this likely because the QPixmap data is device-dependent.

There is a question of whether the ImageEditor should be storing a QPixmap or a QImage - I suspect QPixmap was chosen because that was what was easily available (but maybe for speed/efficiency too).

@corranwebster
Copy link
Contributor Author

LGTM, but a comment explaining why this code is doing what it's doing would be useful.

Done.

@corranwebster corranwebster merged commit 823fb98 into main Feb 24, 2022
@corranwebster corranwebster deleted the fix/qpixmap-memory-issue branch February 24, 2022 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Memory management issues for images under Windows/PySide2
3 participants