javascript - QML 内存泄漏发送 XMLHttpRequest

标签 javascript qt memory 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???
    }
}


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

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

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

类似问题的引用:
QTBUG-43005 (No resolution)
QTBUG-50231 (No resolution)

现在记录在 QTBUG-83857

enter image description here
在这里,拥有 2.0GB 的内存。它保持了将近 4 个小时,直到我终止了该程序。当我关闭应用程序时,大约 60 秒后,整个 2GB 内存被释放

尝试使用 QNetworkAccessManager 类
//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 的说法,不幸的是,这也保留了内存并且不会释放它。

最佳答案

编辑

在 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")));

--

现在您只需注册类型并在 main.cpp 中创建一个实例
 qmlRegisterType<MyClass>("MyClass", 1,0, "MyClass");

--

并在您的 QML 文件中执行
import MyClass 1.0
Window {
   MyClass { 
     id: myNetworkClass
   }

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

这将为您提供一种稳定的方法来避免由于在强类型框架上运行异步且弱类型的原生 javascript 环境而产生的 QML 问题......

祝你好运!

原创

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

将所有 XMLHttpRequest 对象的数组保存在 Window 的属性中
Window
{
    property var requests: []
// ...

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

然后可能开始删除数组中的对象
...
var xhttp = requests.unshift() 
xhttp.destroy()

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

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

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

关于javascript - QML 内存泄漏发送 XMLHttpRequest,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61378389/

相关文章:

检查在 C 中成功创建的数组

iphone - 为什么 UIWebView 不释放其所有内存?

javascript - Jquery find 方法挂起我的整个浏览器

javascript - AngularJS 中的进度处理程序

javascript - <图片> src(事件源)

c++ - 如何有选择地使 QWidget 接受鼠标单击的焦点?

javascript - 了解 Dean Edwards 的附加事件 JavaScript

c++ - 旋转一个矩形

ios - IOS 上的 Qt QML 应用程序运行缓慢,JIT 被禁用

Java ImageIO 将图像 byte[] 读取到预分配的 BufferedImage 中