QObject Automatic Signal Disconnection
Hello all, I'm unsure if this is the appropriate location for this suggestion.
I've been heavily using the QNetworkAccessManager recently for applications which are designed to run for months at a time, I noticed a memory issue which can't be properly classified as a leak.
This small block demonstrates the issue (it could be connected to anything)
Code:
QNetworkReply* reply = network_access_manager.get(request);
connect(reply, SIGNAL(finished()),
&e_l , SLOT(quit()));
e_l.exec();
/* ... */
reply->deleteLater();
After execution of this code, all allocated memory is freed...however somewhere in the QObject world there's reference to reply being connected to e_l. This remains true even if both variables are freed, at which point there's no way to remove the reference (as far as I'm aware) and so it's essentially lost memory. My very rough test found using Qt 4.8.0 Linux x86_64 that .543K was lost per connection which was not disconnected. This behaviour was unexpected to me (even if I am in the wrong) and I'd predict it to cause unexpected leaks for anyone developing with the network utilities. Is there no reason the d-tor of the freed cannot inform the paired object so this reference can be removed?
Re: QObject Automatic Signal Disconnection
Quote:
Originally Posted by
_M_chipz
however somewhere in the QObject world there's reference to reply being connected to e_l. This remains true even if both variables are freed
No, that's not true. There is a piece of code in QObject destructor that breaks all signal-slot connections regarding the object being destroyed.
Code:
// disconnect all receivers
if (d->connectionLists) {
++d->connectionLists->inUse;
int connectionListsCount = d->connectionLists->count();
for (int signal = -1; signal < connectionListsCount; ++signal) {
QObjectPrivate::ConnectionList &connectionList =
(*d->connectionLists)[signal];
while (QObjectPrivate::Connection *c = connectionList.first) {
if (!c->receiver) {
connectionList.first = c->nextConnectionList;
delete c;
continue;
}
QMutex *m
= signalSlotLock
(c
->receiver
);
bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
if (c->receiver) {
*c->prev = c->next;
if (c->next) c->next->prev = c->prev;
}
if (needToUnlock)
m->unlockInline();
connectionList.first = c->nextConnectionList;
delete c;
}
}
if (!--d->connectionLists->inUse) {
delete d->connectionLists;
} else {
d->connectionLists->orphaned = true;
}
d->connectionLists = 0;
}
// disconnect all senders
QObjectPrivate::Connection *node = d->senders;
while (node) {
QMutex *m
= signalSlotLock
(sender
);
node->prev = &node;
bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
//the node has maybe been removed while the mutex was unlocked in relock?
if (!node || node->sender != sender) {
m->unlockInline();
continue;
}
node->receiver = 0;
QObjectConnectionListVector *senderLists = sender->d_func()->connectionLists;
if (senderLists)
senderLists->dirty = true;
node = node->next;
if (needToUnlock)
m->unlockInline();
}
Quote:
My very rough test found using Qt 4.8.0 Linux x86_64 that .543K was lost per connection which was not disconnected.
How exactly did you test it?
Re: QObject Automatic Signal Disconnection
Hello wysota. Apologies, in my test case I was using deleteLater() in a tight loop and using pmap to track memory. It caused more memory to be mapped to the process which tricked me into seeing leak-like behaviour. Changing the test methodology shows there is in fact no issue.
This post can be closed (If such things are done here).