QML 内存泄漏发送 XMLHttpRequest

Tyl*_*r M 6 javascript memory qt memory-leaks qml

创建 的new实例XMLHttpRequest和调用会send()导致垃圾收集器无法清除的内存使用量,也无法清除gc(). 调用delete对象也不会清除内存。

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???
    }
}

Run Code Online (Sandbox Code Playgroud)

如果我从不打电话,xhttp.send()那么我就没有任何内存泄漏。垃圾收集开始,因为没有对 的引用var xhttp并且内存被释放。我想也许垃圾收集器没有触发,但gc()也不会清除内存。

这个 MRE 将运行 100,000 次迭代并在内存中保存大约 500MB。这可以通过更改为 轻松容纳 5.0GB i < 1000000

如何修复此内存泄漏并释放内存?

类似问题参考: QTBUG-43005(无解析) QTBUG-50231(无解析)

现在记录在QTBUG-83857 上

在此处输入图片说明 在这里,持有 2.0GB 的内存。它保持了将近 4 个小时,直到我杀死了该程序。当我关闭应用程序时,大约 60 秒后释放了整个 2GB 内存

尝试使用 QNetworkAccessManager 类

//main.qml
    MyClass {
        id: myNetworkClass

        Component.onCompleted: {
            for(var i = 0; i < 10000; i++) {
                myNetworkClass.doDownload()
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)
//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
Run Code Online (Sandbox Code Playgroud)

不幸的是,根据 htop 的说法,这也会保留内存并且不会释放它。

mik*_*10a 2

编辑

在 C++ 中创建一个新的控制类来处理您的 Web 请求,然后设置根上下文属性或在 QML 中注册类型并使用 C++ api。

这是最简单的方法:

在 myclass.cpp 中,您使用此类代码以及适当的处理程序创建一个方法(replyFinished)

确保要从 QML 调用的方法在头文件中以 Q_INVOKABLE 为前缀(位于 void 之前)

QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished,
        this, &MyClass::replyFinished);

manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
Run Code Online (Sandbox Code Playgroud)

--

现在您只需注册类型并在 main.cpp 中创建一个实例

 qmlRegisterType<MyClass>("MyClass", 1,0, "MyClass");
Run Code Online (Sandbox Code Playgroud)

--

并在你的 QML 文件中执行

import MyClass 1.0
Window {
   MyClass { 
     id: myNetworkClass
   }

  function doLookup() { myNetworkClass.myCustomMethod(); }
}
Run Code Online (Sandbox Code Playgroud)

这将为您提供一种稳定的方法来避免因运行本机 javascript 环境而产生的 QML 问题,该环境是异步且弱类型的强类型框架...

祝你好运!

原来的

首先,您通过创建请求来保留挂起的对象引用,而不保存对所创建对象的引用......

将所有 XMLHttpRequest 对象的数组保留在 Window 的属性中

Window
{
    property var requests: []
// ...

    Timer {
       onTriggered: { 
 //  add request to array
             requests.push(xhttp);
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后也许开始删除数组中的对象......

var xhttp = requests.unshift() 
xhttp.destroy()
Run Code Online (Sandbox Code Playgroud)

但真正的问题在于以 50 毫秒的间隔发送 http 请求

那就是每秒 20 个或每分钟 1200 个请求

您可能需要调整代码以在前一个请求完成后发送请求..或将间隔设置为更高的值