[PyQt] QImage memory leak in 4.10.1

Phil Thompson phil at riverbankcomputing.com
Fri Jun 21 10:56:18 BST 2013


On Tue, 18 Jun 2013 19:14:35 -0400, Luke Campagnola
<lcampagn at email.unc.edu> wrote:
> On Fri, May 24, 2013 at 1:42 PM, Phil Thompson
> <phil at riverbankcomputing.com>wrote:
> 
>> On Thu, 23 May 2013 16:21:26 -0400, Luke Campagnola
>> <lcampagn at email.unc.edu> wrote:
>> > Howdy,
>> > I am using PyQt 4.10.1 (Py2.7-qt4.8.4-x32) on windows XP. It appears
>> that
>> > on this system, QImage(sip.voidptr, int, int, format) increases the
>> > reference count to the image data object, but does not decrease the
>> > refcount after the QImage is collected. Here's an example session,
>> > where
>> I
>> > am generating a QImage from a numpy array:
>> >
>> >>>> from PyQt4 import QtGui
>> >>>> import ctypes, weakref, sys
>> >>>> import numpy as np
>> >>>> data = np.zeros((100,100,4), dtype=np.ubyte)
>> >>>> addr = ctypes.c_char.from_buffer(data,0)
>> >>>> sys.getrefcount(addr)
>> > 2
>> >>>> img = QtGui.QImage(addr, 100, 100, QtGui.QImage.Format_ARGB32)
>> >>>> sys.getrefcount(addr)   # QImage added 1 to reference count
>> > 3
>> >>>> import weakref
>> >>>> ref = weakref.ref(img)
>> >>>> del img
>> >>>> ref
>> > <weakref at 0161F090; dead>  # QImage was collected
>> >>>> sys.getrefcount(addr)  # but refcount is still 3
>> > 3
>> >
>> >
>> > Can anyone recommend a good way to convert from ndarray to QImage
>> > (preferrably without incurring any memory copy) ?
>>
>> Using either a sip.voidptr or a string seems to work fine for me with
>> current snapshots.
>>
> 
> Thanks, Phil. I'd like to revisit this (as well as an older, related
> question) a bit since we're still having trouble with them. I've boiled
the
> problem down a bit more and it appears entirely within sip.voidptr (or
my
> usage of sip.voidptr). First, the control, running under 4.9.3:
> 
> import sip, numpy, gc
> arr = numpy.zeros(100000000, dtype=numpy.ubyte)
> ptr = sip.voidptr(arr.ctypes.data)
> del arr, ptr
> gc.collect()
> 
> 
> This code runs as expected. Note that the argument to sip.voidptr is an
> integer, the memory address of the array data.
> Now the trouble, running under 4.10.2:
> 
> import sip, numpy, gc
> arr = numpy.zeros(100000000, dtype=numpy.ubyte)
> ptr = sip.voidptr(arr)
> del arr, ptr
> gc.collect()
> 
> 
> This code leaks the 100MB array. If I inspect with sys.getrefcount, I
see
> that the array has picked up some extra counts that were not removed
after
> the voidptr is deleted. Note also that the argument to sip.voidptr here
is
> the numpy array itself. If I try passing an integer to sip.voidptr under
> 4.10.2, I get the error "TypeError: a single integer, Capsule, CObject,
> None, buffer protocol implementor or another sip.voidptr object is
> required". Likewise, I get the same error if I pass the array directly
to
> sip.voidptr under 4.9.3.
> 
> So I have two questions about this code:
> 
> 1) Is there some way to avoid the memory leak in 4.10.2?
> 2) Can you tell me when the API change to sip.voidptr occurred?
> 
> Thanks very much! I really appreciate the effort and support you have
put
> into this project.

The attached SIP patch should fix the reference count bug.

If you still have a problem converting an int to a sip.voidptr then I need
a test that demonstrates the problem.

Phil
-------------- next part --------------
A non-text attachment was scrubbed...
Name: voidptr.c.patch
Type: text/x-diff
Size: 330 bytes
Desc: not available
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20130621/f2d2999e/attachment.patch>


More information about the PyQt mailing list