[Development] leak in QMetaObject?

Thiago Macieira thiago.macieira at intel.com
Thu Jul 14 20:39:31 CEST 2016

On quinta-feira, 14 de julho de 2016 19:08:11 PDT Thomas Senyk wrote:
> On 14.07.2016 18:56, Thiago Macieira wrote:
> > On quinta-feira, 14 de julho de 2016 18:37:17 PDT Thomas Senyk wrote:
> >> On 14.07.2016 18:25, Thiago Macieira wrote:
> >>> On quinta-feira, 14 de julho de 2016 17:45:58 PDT Thomas Senyk wrote:
> >>>> should "fix" it? .. but I still see 100% cpu and same memory
> >>>> consumption?
> >>> 
> >>> Can you attach the debugger to see what it is still doing after you're
> >>> done?
> >> 
> >> Still the same, goes in circles around in QMetaObject::activate
> >> 
> >> #3671 => #3673 =>  if (!c->receiver) continue => while => ...
> >> ... pressing F10 for a while doesn't let you out of that (short) cycle.
> >> 
> >> If you want to know (I know it's not saying much) the values for
> >> list->first and list->last: @0x1529ac0, @0x6a3a3250
> >> 
> >> 
> >> Is that what you wanted to know? If I misunderstood, please clarify :)
> > 
> > I wanted a backtrace. Are you saying the trace is 3700 frames deep?
> Sorry that was line numbers :) No it's not.
> http://paste.ofcode.org/u3gGqxAfX9hWefeUszDEx
> About to generate a callgrind output.

It's a little hard to tell from your backtrace. The Qt Creator copy & paste is 
never the right thing, since it doesn't include function parameters. Please 
use the gdb "bt" command whenever possible. That means debugging outside 
Creator, since Creator can't get the output from that. If that is too difficult, 
the "full backtrace" is a good compromise.

Anyway, I think your test is faulty. When you write:

            if ((i%10000000)==0) {
                QObject::connect(t, &QTimer::timeout, []() {
                    qDebug() << "test .. it should be empty now?";

First of all, why did you use a modulo instead of straight up comparison?

Anyway, as far as I can tell, the sender (the QTimer) connectionLists vector 
contains 4 entries, only one of which is non-empty. That's the one 
corresponding to the timeout() signal. Each connection list is a *singly* 
linked list, so it has O(n) behaviour and your n is 10 million.

We talked about cleanConnectionLists. But that function starts with 

    if (connectionLists->dirty && !connectionLists->inUse) {

For the first 10 million times this function is called, the "dirty" flag is 
false. Then your lambdas start getting called and set the "dirty" flag to true.

On the 10 million + 1 time that the function is called, from that connect() 
call above, "dirty" is true, but so is "inUse", because you're in the middle 
of delivering signals. 

So the list isn't cleaned.

After this, there's only one slot connected to the signal, but the list is 10M
+1 items long.

Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center

More information about the Development mailing list