[PyQt] QImage memory leak in 4.10.1

Luke Campagnola lcampagn at email.unc.edu
Wed Jun 19 00:14:35 BST 2013


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.


Luke
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20130618/0934c182/attachment.html>


More information about the PyQt mailing list