Good resource on how to use QNetworkAccessManager & QNetworkReply correctly?
-
Detecting an issue is probably something as simple as attaching a QTimer and having it check the upload progress of your message every second or something: after a few seconds of no change, call that a timeout, and start dumping the queued items to the disk instead. Unless your messages are very large or very frequent, I'd think that you could easily queue up, say 5-10 seconds before you start storing them locally.
-
I appreciate the guidance! I'll see if I can mash something together and update the post if I can get it to work the way I need it to.
I wish there were more content (examples) out there for QNetwork guidance. I like to build off examples.
-
I found a great article in the "Qt Quarterly" that talked about GUIs freezing during long operations. It seemed to fit my scenario, so here's how I decided to implement it to solve my logging to a web server problem:
@
void Logger::log(QString msg)
{
loggerUrl.append("/" + msg);if (DEBUG > 8) qDebug() << "log url:" << loggerUrl; request.setUrl(QUrl(loggerUrl)); managerReply = manager->get(request); timer->start(5000); // give the web server 5s to respond loop->exec(); // QEventLoop created on setup to convert async ops to sync using SIGNAL/SLOT if (timer->isActive()) { // log upload complete qDebug() << "upload complete"; timer->stop(); } else { // timeout qDebug() << "manager timed out"; managerReply->abort(); managerReply->deleteLater(); // Log to local disk and process later }
}
@ -
Well. The saga continues. Now I have a memory leak (albeit a small one) with either the QTimer or the QEventLoop. I've run it through valgrind to trim out as much as I could and it did find some issues that I fixed, but it still leaks if I use this routine with the timeout code. Any ideas where I'm losing memory? It's ~400KB per every 100 executions of this function.
@
bool Logger::logNetwork(QString &msg)
{
QTimer timer;
timer.setSingleShot(true);QEventLoop loop; connect(&timer,SIGNAL(timeout()),&loop,SLOT(quit())); connect(manager,SIGNAL(finished(QNetworkReply*)),&loop,SLOT(quit())); QString logUrl = msg; if (!msg.startsWith("http")) { QStringList fields = msg.split(" "); logUrl = loggerUrl; } if (DEBUG > 8) qDebug() << "log url:" << logUrl; request.setUrl(QUrl(logUrl)); QNetworkReply *managerReply = manager->get(request); timer.start(5000); // give the web server 5s to respond loop.exec(); if (timer.isActive()) { // log upload complete try { qDebug() << "stop timer"; timer.stop(); } catch (int i) { qDebug() << "timer.stop() emitted an error"; } timer.deleteLater(); return true; } else { // timed out networkSuccess = false; managerReply->abort(); managerReply->deleteLater(); return false; }
}
@ -
Calling timer.deleteLater() is an absolute no-go and can crash your application. The timer is deleted on leaving method logNetwork, as it is stack allocated. You must not call delete (or deleteLater) on a stack based variable.
In the if branch the handles the not time out case, you do not delete the managerReply (resp. do not call managerReply->deleteLater()).
-
Actually, I added the timer.deleteLater() further into the debug process. I originally didn't have it in there. As for the managerReply->deleteLater(), I thought I read somewhere in the docs that I HAD to delete it myself and that the way to do it was with deleteLater? At any rate, in the initial testing no timeout is reached. So the "else" section isn't hit. I know this because I'm returning "true" during the initial test.
When I comment out the timer & loop stuff and just return true after manager->get(request), it doesn't seem to hold on to memory. Granted, I'm looking at top output and watching the web server log to determine usage and run count. But in the tests w/o timer & loop, I don't see the same memory climb stats I see with them.
I'm wondering if maybe it has to do with there being a QList<T> in either of these classes and it's not being deleted, cleared or reassigned? I think I read something about the difference between QList & QVector and how it allocates to the heap.
-
top is not a reliable means to check for memory leaks.
For when to delete - this is plain C++ basics:
- if you allocate on the stack you don't need to do anything
the object is deleted once it goes out of scope - if you allocate on the heap using new, you must call delete
** directly: <code>delete obj;</code>
** delayed: <code>obj.deleteLater()</code> if it's QObject based
** indirectly: by passing a parent QObject to the QObject based object
the parent will eventually delete the child object once itself is deleted - if you allocate an array on the heap using <code>new[]</code>, you must call <code>delete[]</code>
- if you allocate on the heap using malloc, you must call free
And you never ever must mix the three toplevel approaches. Calling delete on an malloc'ed object or calling free on a new'ed object or calling free/delete on a stack based object leads to earth destruction eventually. This is one of the very rare occasions where "never" is appropriate in programming C++.
For the QList question: Sorry, the crystal balls are still on new year's holidays, so please accept that we cannot comment on this.
- if you allocate on the stack you don't need to do anything
-
OUCH! The back of my hands are starting to turn red! ;-)
So reading between the lines, I should ignore the fact that I can see a repeatable difference in the memory usage (albeit from top) between using the QTimer/QEventLoop and not?!?!?
-
its kind of difficult
-
[quote author="shorawitz" date="1325697752"]OUCH! The back of my hands are starting to turn red! ;-)
So reading between the lines, I should ignore the fact that I can see a repeatable difference in the memory usage (albeit from top) between using the QTimer/QEventLoop and not?!?!?[/quote]
top is not a tool to debug memory leaks! It's ok to use it to monitor the overall trend of the memory consumption of an application, but nothing more please! If you need to hunt down memory leaks, use a dedicated tool like valgrind. Qt Creator even has support for it.
-
I did use valgrind, but I didn't see any noticeable information to point to a specific class/function that was causing the memory leak. I'll keep fiddling with the various options to valgrind and update my Qt libs to something newer that 4.7.2