From c247aa3989cc5b375dcf27c7eb0931770a85d134 Mon Sep 17 00:00:00 2001 From: Justin Engel Date: Tue, 11 Apr 2017 10:32:43 -0400 Subject: [PATCH 1/2] Fixed PySide image memory leak PySide has a known memory leak issue when using QImage. It does not handle the reference counter correctly. I manually adjusted the reference counter to the data as suggested in a bug report by Neil Whelchel. This bug report can be found at https://bugreports.qt.io/browse/PYSIDE-140 --- pyqtgraph/functions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyqtgraph/functions.py b/pyqtgraph/functions.py index 839720d1..73dec8b6 100644 --- a/pyqtgraph/functions.py +++ b/pyqtgraph/functions.py @@ -1188,7 +1188,9 @@ def makeQImage(imgData, alpha=None, copy=True, transpose=True): if USE_PYSIDE: ch = ctypes.c_char.from_buffer(imgData, 0) + rcount = ctypes.c_long.from_address(id(ch)).value # Get the reference count of self.data. img = QtGui.QImage(ch, imgData.shape[1], imgData.shape[0], imgFormat) + ctypes.c_long.from_address(id(ch)).value = rcount # This puts the refcount back where it belongs. else: #addr = ctypes.addressof(ctypes.c_char.from_buffer(imgData, 0)) ## PyQt API for QImage changed between 4.9.3 and 4.9.6 (I don't know exactly which version it was) From f6819dda28e9f725215efb5f198257a43b827d38 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Mon, 1 May 2017 11:09:50 -0700 Subject: [PATCH 2/2] Add comments explaining hack --- pyqtgraph/functions.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pyqtgraph/functions.py b/pyqtgraph/functions.py index 73dec8b6..8b2e4684 100644 --- a/pyqtgraph/functions.py +++ b/pyqtgraph/functions.py @@ -1188,9 +1188,20 @@ def makeQImage(imgData, alpha=None, copy=True, transpose=True): if USE_PYSIDE: ch = ctypes.c_char.from_buffer(imgData, 0) - rcount = ctypes.c_long.from_address(id(ch)).value # Get the reference count of self.data. + + # Bug in PySide + Python 3 causes refcount for image data to be improperly + # incremented, which leads to leaked memory. As a workaround, we manually + # reset the reference count after creating the QImage. + # See: https://bugreports.qt.io/browse/PYSIDE-140 + + # Get initial reference count (PyObject struct has ob_refcnt as first element) + rcount = ctypes.c_long.from_address(id(ch)).value img = QtGui.QImage(ch, imgData.shape[1], imgData.shape[0], imgFormat) - ctypes.c_long.from_address(id(ch)).value = rcount # This puts the refcount back where it belongs. + if sys.version[0] == '3': + # Reset refcount only on python 3. Technically this would have no effect + # on python 2, but this is a nasty hack, and checking for version here + # helps to mitigate possible unforseen consequences. + ctypes.c_long.from_address(id(ch)).value = rcount else: #addr = ctypes.addressof(ctypes.c_char.from_buffer(imgData, 0)) ## PyQt API for QImage changed between 4.9.3 and 4.9.6 (I don't know exactly which version it was)