Утечка памяти QML при отправке XMLHttpRequest - PullRequest
6 голосов
/ 23 апреля 2020

Создание 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 итераций и в памяти будет занимать около 500 МБ. Это может легко вместить 5,0 ГБ, изменив значение i < 1000000.

Как я могу исправить эту утечку памяти и освободить память?

Ссылки на похожие вопросы: QTBUG-43005 (Нет разрешение) QTBUG-50231 (без разрешения)

Теперь задокументировано на QTBUG-83857

enter image description here Вот оно, 2,0 ГБ памяти. Это держало это в течение почти 4 часов, пока я не убил программу. Когда я закрыл приложение, примерно через 60 секунд освободилась вся 2 ГБ памяти

Попытка использования класса 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.

1 Ответ

2 голосов
/ 24 апреля 2020

РЕДАКТИРОВАТЬ

Создайте новый управляющий класс в C ++ для обработки ваших веб-запросов, затем установите свойство контекста root или зарегистрируйте тип в QML и используйте вместо этого API-интерфейс C ++.

Вот самый простой способ go:

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

-

Теперь вы просто регистрируете тип и создаете экземпляр в основном. cpp

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

-

и в своем файле QML выполните

import MyClass 1.0
Window {
   MyClass { 
     id: myNetworkClass
   }

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

Это даст вам стабильный способ избежать проблем с QML это происходит из-за запуска собственной javascript среды, которая асинхронна и слабо типизирована в строго типизированной среде ...

Удачи!

ORIGINAL

Во-первых, вы оставляете привязанные ссылки на объекты, создавая То есть без сохранения ссылки на созданный объект ...

Храните массив всех объектов XMLHttpRequest в свойстве Window

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

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

Затем, возможно, начните удалять объекты в вашем массиве с помощью. ..

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

Но реальная проблема заключается в отправке http-запросов с интервалами 50 мс

Это 20 мм / сек или 1200 / мин запросов

Возможно, вы захотите настроить код для отправки запроса после завершения предыдущего .. или для более высокого значения интервала

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...