2017-01-04 16 views
0

Я использую QThread для печати работ с помощью QPrinterУтечка памяти при использовании QThread и QPrinter

Мой PrintWorker выглядеть следующим образом:

class PrintWorker : public QObject { 
    Q_OBJECT 

public: 
    PrintWorker(QThread*, QPrinter*, QPicture*, QPainter*, QObject *parent = 0); 

private: 
    QPicture *_picture = nullptr; 
    QPrinter *_printer = nullptr; 
    QPainter *_painter = nullptr; 

    public slots: 
    void print(); 

signals: 
    void done(); 
}; 

PrintWorker::PrintWorker(QThread *thread, QPrinter *printer, QPicture *picture, QPainter *painter, QObject *parent) :QObject(parent), 
_picture(picture), _printer(printer), _painter(painter) 
{ 
    moveToThread(thread); 
    QObject::connect(thread, &QThread::started, this, &PrintWorker::print); 
    QObject::connect(this, &PrintWorker::done, thread, &QThread::quit); 
    QObject::connect(this, &PrintWorker::done, this, &PrintWorker::deleteLater); 
    QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); 
} 

void PrintWorker::print() { 
    // do some print job with painter and picture 
    emit done(); 
} 

И print Метод заключается в следующем:

void NewService::print() { 
    if (!_printer) { /* _printer : a private member */ 
     _printer = new QPrinter(QPrinter::HighResolution); 
     _printer->setPageSize(QPrinter::A5); 
     _printer->setPageOrientation(QPageLayout::Portrait); 
     _printer->setColorMode(QPrinter::Color); 
    } 

    if (!_printDialog) { /* _printDialog : a private member */ 
     _printDialog = new QPrintDialog(_printer); 
    } 

    if (_printDialog->exec() == QPrintDialog::Accepted) { 
     MyWidget *widget = new MyWidget(/* some args*/); 

     QPainter *painter = new QPainter; 
     QPicture *picture = new QPicture; 
     widget->render(picture); 

     QThread *thread = new QThread; 
     PrintWorker *worker = new PrintWorker(thread, _printer, picture, painter); 
     thread->start(); 
    } 
} 

Теперь перед вызовом print() мое приложение выдает около 9 МБ памяти после печати и вызова PrintWorker::print() Использование памяти моего приложения до 26 МБ

В другом мире, если мы удалим emit done на последней части в PrintWorker::print(), это не имеет значения.

Что мы ожидаем после окончания работы является использование памяти должна получить до 26 Мб - темы пространство + _printer + _printDialog объекты размером ≈ 14MB

Так что случилось с этим?

+0

вы пытались добавить QDebug увидеть, если деструктор вашего печати работника вызывался? –

+0

@ rafaelgonzalez.Yes 'PrintWorker :: ~ PrintWorker()' вызывается. – IMAN4K

ответ

0

Вы удаляете PrintWorker и QThread объекты, но не QPainter, QPicture, MyWidget, QPrintDialog ни QPrinter. Это утечки памяти (new без delete). Обратите внимание, что деструктор PrintWorker может позаботиться об удалении QPainter, QPicture и QPrinter, кроме того, он также может стать владельцем MyWidget и удалить его. Надеюсь, объект QPrintDialog будет удален классом NewService, но его сложно сказать, поскольку код не был отправлен.

Кроме того, по рекомендации rafael gonzalez, вы должны убедиться, что QThreadPrintWorker и QThread на самом деле удаляются.

Кстати, как вы проверили использование памяти? Через инструмент обнаружения утечки (например, valgrind, VLD ...)? Или через диспетчер задач Windows. Поскольку диспетчер задач определенно неточен.

+0

Да, инструмент измерения - диспетчер задач Windows, а также Да PrintWorker :: ~ PrintWorker() вызывается, и я не получаю его. Я делаю свой объект потока закрытым и устанавливаю 'QObject :: connect (_printThread, & QThread :: destroy, this , & NewService :: onPrintDone); 'теперь я вижу' QObject (0x2647bb040f0) 'через' qDebug() << _printThread; '!! поэтому он не удаляется. – IMAN4K

+0

Удаление '_printThread' не изменит адрес указателя, он все равно может отображать' QObject (0x2647bb040f0) 'даже если он удален.Кроме того, onPrintDone может вызываться до того, как 'QThread' фактически удаляется механизмом' deleteLater'. Наконец, диспетчер задач показывает использование памяти вашего приложения, которое не обязательно сокращается при удалении объекта. Вы должны использовать инструмент течеискателя. – jpo38

0

Вызывая QThread::quit(), вы активно выходите из EventLoop в этой теме. A QObject::deleteLater() для объектов, проживающих в этой теме, может не выполняться больше (хотя они упоминают в QThread::finished() -signal, что и последующий слот удаления по-прежнему будет вызываться).

Я лично просто установил соединение, используя сигнал finished(), или установил родительский объект рабочего объекта как сам поток, тогда Qt действительно должен удалить объект.

http://doc.qt.io/qt-5/qthread.html#exit