繁体   English   中英

QML Memory 泄漏发送 XMLHttpRequest

[英]QML Memory leak sending XMLHttpRequest

创建XMLHttpRequestnew实例并调用send()会导致垃圾收集器无法清除 memory 的使用,也无法清除gc() 在 object 上调用delete也不会清除 memory。

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

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

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

如何修复此 memory 泄漏并释放 memory?

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

现在记录在QTBUG-83857

在此处输入图像描述 在这里,持有 2.0GB 的 memory。 它保持了将近 4 个小时,直到我终止了该程序。 当我关闭应用程序时,大约 60 秒后,整个 2GB memory 被释放

尝试使用 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

根据 htop 的说法,不幸的是,这也保留了 memory 并且没有释放它。

编辑

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.

这是 go 的最简单方法:

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

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

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

manager->get(QNetworkRequest(QUrl("http://qt-project.org")));

--

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

 qmlRegisterType<MyClass>("MyClass", 1,0, "MyClass");

--

并在您的 QML 文件中执行

import MyClass 1.0
Window {
   MyClass { 
     id: myNetworkClass
   }

  function doLookup() { myNetworkClass.myCustomMethod(); }
}

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

祝你好运!

原来的

首先,通过创建请求而不保存对创建的 object 的引用,您将挂起 object 引用...

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

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

    Timer {
       onTriggered: { 
 //  add request to array
             requests.push(xhttp);
       }
    }
}

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

var xhttp = requests.unshift() 
xhttp.destroy()

但真正的问题是每隔 50 毫秒发送 http 请求

那是 ummm 每秒 20 个或 1200 个/分钟的请求

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM