[PyKDE] Re: Memory leak & segfault with deleteLater

Phil Thompson phil at riverbankcomputing.co.uk
Wed Aug 10 18:14:29 BST 2005


Giovanni,

Remember this?

I have a potential fix for this disabled in tonight's SIP snapshot. To try it 
out change the #if 1 in sip_api_common_dtor() in siplib.c to #if 0.

What the fix does is to prevent the removal of the hidden extra reference and 
leaves it to the cyclic garbage collector to deal with it.

There are some issues with this...

1. A collect could be run while we are still in the C++ dtor (unlikely but 
possible) and there would still be a segfault.

2. w1 and it's C++ instance won't be garbage collected (and the widget might 
be visible) until the collector is run. Might this be too long to wait? (It 
would be possible to explicitly run the collector at strategic points in the 
sip module.)

I'm still inclined to say it's a bug in the application.

Opinions?

Phil

On Monday 20 June 2005 9:22 pm, Phil Thompson wrote:
> On Monday 20 June 2005 4:15 pm, Giovanni Bajo wrote:
> > Hello,
> >
> > two problems, which are very similar (and maybe related). The first is a
> >
> > segmentation fault:
> > >>> from qt import *
> > >>> app = QApplication([])
> > >>> w1 = QWidget(None)
>
> w1 reference count is 1.
>
> > >>> w2 = QWidget(w1)
>
> w2 reference count is 2. This is because ownership of w2 is with C++
> because it has a parent. The extra reference is needed to make sure
> valuable data isn't lost if the application doesn't keep a reference to the
> child.
>
> > >>> w2.xxxx = w1
>
> w1 reference count is 2.
>
> > >>> w2.deleteLater()
>
> A DeferredDelete event is posted to w2.
>
> > >>> del w1
>
> w1 reference count is 1.
>
> > >>> del w2
>
> w2 reference count is 1.
>
> > >>> app.processEvents()
>
> w2 handles the DeferredDelete event and calls it's own virtual dtor. This
> is "caught" by the dtor of an internally generated QWidget sub-class which
> removes w2's extra reference. w2 reference count is now 0.
>
> Python now garbage collects w2, part of which is to reduce the reference
> count of w1 to 0. As w1 is owned by Python (because the C++ instance
> doesn't have a parent) it calls the C++ dtor. This then calls the C++ dtor
> of it's children (ie. w2) - but we are already in w2's dtor. The problem is
> that we haven't yet executed the base QObject dtor which removes an
> instance from it's parent and would prevent the recursive dtor call.
>
> > Segmentation fault
> >
> > The thing I don't understand is why it does not crash if you don't add a
> > reference to w1 from inside w2.
>
> w1 will be garbage collected by "del w1". This will cause the C++ dtors for
> w2 and w1 to execute. The w2 dtor will remove the extra reference to w2
> (leaving it at 1).
>
> "del w2" will then cause w2 to be garbage collected. Nothing extra happens
> here because PyQt knows that the wrapped C++ instance has already gone.
>
> I'm not sure if anything can be done to detect and/or prevent the problem.
> It would be easy enough to contrive the same problem in C++, so I don't
> really see it as a PyQt problem. I'm open to suggestions.
>
> > The second problem is a memory leak:
>
> I'll think about this tomorrow - my head hurts at the moment.
>
> Phil




More information about the PyQt mailing list