Creating new
instances of XMLHttpRequest
and calling send()
results in memory usage that can't be cleared by the garbage collector, nor gc()
. Calling delete
on the object doesnt' clear the memory neither.
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 480
Component.onCompleted: {
for(var i = 0; i < 100000; i++) {
console.log("Send request " + i)
var xhttp = new XMLHttpRequest
xhttp.open('get', 'someurl')
xhttp.send()
delete xhttp
}
gc() //why won't this clean the instances of XMLHttpRequest???
}
}
If I never call xhttp.send()
then I don't have any memory leak. Garbage collection kicks in since there's no reference to the var xhttp
and the memory is freed. I thought maybe the garbage collector wasn't triggering, but gc()
wouldn't clear the memory neither.
This MRE will run 100,000 iterations and holds about 500MB in memory. This can easily hold 5.0GB by changing to i < 1000000
.
How do I fix this memory leak and free the memory?
References to similar questions: QTBUG-43005 (No resolution) QTBUG-50231 (No resolution)
Now documented on QTBUG-83857
Here it is, holding 2.0GB of memory. It held it for nearly 4 hours until I killed the program. When I closed the application, after about 60 seconds the whole 2GB memory was freed
An Attempt at using QNetworkAccessManager class
//main.qml
MyClass {
id: myNetworkClass
Component.onCompleted: {
for(var i = 0; i < 10000; i++) {
myNetworkClass.doDownload()
}
}
}
//myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QDebug>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0):QObject(){
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
}
public:
Q_INVOKABLE void doDownload() {
manager->get(QNetworkRequest(QUrl("https://esi.evetech.net/latest/characters/93610700")));
}
public slots:
void replyFinished(QNetworkReply *reply) {};
private:
QNetworkAccessManager *manager;
int count = 0;
};
#endif // MYCLASS_H
This unfortunately also holds onto memory and doesn't release it, according to htop.
EDIT
Create a new controlling class in C++ to handle your web requests and then set a root context property or register the type in QML and use the C++ api instead.
Here's the simplest way to go:
in myclass.cpp you create a method with this type of code along with the appropriate handlers (replyFinished)
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished,
this, &MyClass::replyFinished);
manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
--
qmlRegisterType<MyClass>("MyClass", 1,0, "MyClass");
--
and in your QML file do
import MyClass 1.0
Window {
MyClass {
id: myNetworkClass
}
function doLookup() { myNetworkClass.myCustomMethod(); }
}
This will give you a stable way to avoid the QML issues that stem from running a native javascript environment which is asynchronous and weakly typed on a strongly typed framework...
Good luck!
ORIGINAL
First off, you are leaving hanging object references by creating the request without saving a reference to the created object...
Keep an array of all XMLHttpRequest objects in a property of Window
Window
{
property var requests: []
// ...
Timer {
onTriggered: {
// add request to array
requests.push(xhttp);
}
}
}
Then maybe start deleting the objects in your array with ...
var xhttp = requests.unshift()
xhttp.destroy()
But the real issue is in sending http requests at 50ms intervals
Thats ummm 20 per second or 1200/minute requests
You might want to adjust the code to send a request once the previous one finishes.. or set the interval to a higher value
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With