Проблемы с памятью QNetworkAccessManager

Я разрабатываю приложение, которое отправляет запросы на сервер с помощью QtNetworkAccessManager и сохраняет ответы. Я заставил это работать, но использование памяти постоянно увеличивается, пока не заблокирует весь компьютер. Я думаю, что проблема связана с вызовом deletelater() и циклом событий, но я не вижу, как это исправить. Вот код:

main.cpp

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ReadConfig();
    Ethernet M2;
    return a.exec();
}

Ethernet.ч

class Ethernet : public QObject
{
    Q_OBJECT

public:
    Ethernet();
    ~Ethernet();
    QTimer *timer;

private
    QNetworkAccessManager *manager;

public slots:
    void Cycle();
    void replyAuthenticationRequired(QNetworkReply *reply, QAuthenticator *auth);
    void replyFinished(QNetworkReply *reply);
};

Ethernet.cpp

Ethernet::Ethernet() 
{
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(Cycle()));
    timer->start(1000);

    manager = new QNetworkAccessManager(this);
    connect(manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this, SLOT(replyAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
    connect(manager, SIGNAL(finished(QNetworkReply*)), this,     SLOT(replyFinished(QNetworkReply*)));
}

void Ethernet::Cycle()
{
    for (BYTE i=0; i< NUM_TOTAL_VEHICLES; i++)
    {
        FailCheck(i,FILTER_VALUE_PRIORITY_A1);
        FailCheck(i,FILTER_VALUE_PRIORITY_A);
        FailCheck(i,FILTER_VALUE_PRIORITY_B);
        FailCheck(i,FILTER_VALUE_PRIORITY_C);
    }
}

void Ethernet::FailCheck (BYTE coach, BYTE priority)
{
    //Build a valid URL
    QString qsURL = "http://";
    ...
    ..
    .
    //

    manager->get(QNetworkRequest(QUrl(qsURL)));
}

void Ethernet::replyAuthenticationRequired(QNetworkReply *reply, QAuthenticator *auth)
{
   if(!reply->error())
   {
       auth->setUser(DB_USR);
       auth->setPassword(DB_PWD);
   }
   reply->deleteLater();
}

void Ethernet::replyFinished (QNetworkReply *reply)
{
    if(!reply->error())
    {
        //Do some task with the reply;
    }
    reply->deleteLater();
}

Я буду признателен за любые предложения. Благодарю вас!


person Puccinih    schedule 10.05.2016    source источник
comment
у вас нет цикла событий в вашем классе Ethernet, поэтому deleteLater - не работает   -  person tty6    schedule 10.05.2016
comment
Код, который вы разместили, не может быть скомпилирован, ваш класс Ethernet имеет слоты и макрос Q_OBJECT, но не наследует QObject, каков ваш фактический код?   -  person ixSci    schedule 10.05.2016
comment
Спасибо за ваши ответы. Мой класс Ethernet наследуется от QThread, потому что раньше он был потоком, но не больше. Итак, реальная реализация класса — class Ethernet :: public QThread. Я поправил в основном посте.   -  person Puccinih    schedule 10.05.2016


Ответы (3)


Если ваш класс не является потоком, он не должен наследовать QThread. Унаследуйте его от QObject или, если не можете, начните свой M2 поток. Прямо сейчас ваш цикл потоков для Ethernet не работает, и кажется, что сетевые ответы имеют сходство с вашим циклом событий Ethernet (запросы на их удаление отправляются в цикл событий Ethernet, который не запущен)< /с>.

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

person ixSci    schedule 10.05.2016
comment
Я изменил класс Ethernet на class Ethernet : public QObject, но проблема осталась. - person Puccinih; 10.05.2016
comment
@Puccinih, убедитесь, что вы сделали чистую сборку и что слоты replyAuthenticationRequired и replyFinished вызываются - person ixSci; 10.05.2016
comment
Слоты вызывались с самого начала, но это правда, что всего несколько раз. Теперь, после изменения наследования класса на QObject и создания чистой сборки, это кажется решенным. Я проведу еще несколько тестов с сервером, чтобы убедиться, что он действительно работает нормально. Благодарю вас! - person Puccinih; 10.05.2016

Вам нужно создать подкласс Ethernet из QObject, чтобы правильно использовать цикл событий.

person tty6    schedule 10.05.2016
comment
Он вызывает QCoreApplication::exec(), который запускает цикл обработки событий. - person Karsten Koop; 10.05.2016
comment
@KarstenKoop, если ваш класс не является подклассом QObject, он не может использовать цикл событий - person tty6; 10.05.2016
comment
Цикл событий не связан с объектами, поэтому ваш ответ вводит в заблуждение — вам не нужно создавать подклассы, чтобы использовать цикл событий - person ixSci; 10.05.2016

Вы не должны создавать несколько объектов QNetworkAccessManager. Как говорится в документе, «одного QNetworkAccessManager должно быть достаточно для всего приложения Qt». Ссылка. Если вы создадите несколько объектов класса Ethernet, это создаст проблему с памятью. И вам также нужно сделать QObject базовым классом Ethernet.

manager = new QNetworkAccessManager(this);
this (Ethernet) must have QObject as base class.
person code monk    schedule 10.05.2016