2017-01-04 4 views
0

ich QThread für den Druck der Arbeit über QPrinterSpeicherleck, wenn QThread und QPrinter mit

Mein PrintWorker sieht wie folgt mit:

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(); 
} 

Und print Methode ist folgende:

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(); 
    } 
} 

Vor dem Aufruf von print() macht meine App nach dem Drucken und Aufruf vonca. 9MB Speicher verfügbarmeine Speicherauslastung der App erhalten 26MB

In einer anderen Welt, wenn wir emit done letzten Teil entfernen in PrintWorker::print() macht es keinen Unterschied.

Was wir nach Beendigung der Arbeit erwarten ist die Speichernutzung zu 26MB herunterkommen sollte - Gewinde Raum + _printer + _printDialog Objekte Größe ≈ 14MB

So was mit diesem falsch?

+0

haben Sie eine qDebug sehen, ob der destructor Ihres Druck Arbeiter genannt wird immer hinzuzufügen versucht? –

+0

@ rafaelgonzalez.Ja 'PrintWorker :: ~ PrintWorker()' wird aufgerufen. – IMAN4K

Antwort

0

Du PrintWorker und QThread Löschen von Objekten, aber nicht QPainter, QPicture, MyWidget, QPrintDialog noch QPrinter. Das sind Speicherlecks (new ohne delete). Beachten Sie, dass PrintWorker destructor könnte das Löschen von QPainter, QPicture und QPrinter kümmern, additionnaly könnte es auch Besitz von MyWidget übernehmen und löschen. Hoffentlich QPrintDialog Objekt wird von NewService Klasse gelöscht, aber es ist schwer zu sagen, wie Code nicht veröffentlicht wurde.

Auch, wie von Rafael Gonzalez empfohlen, sollten Sie überprüfen, dass QThreadPrintWorker und QThread tatsächlich gelöscht werden.

Wie haben Sie übrigens die Speichernutzung überprüft? Durch ein Lecksuche-Tool (wie Valgrind, VLD ...)? Oder über den Windows Task-Manager. Weil Task-Manager definitiv nicht ausreichend ist.

+0

Ja das Messwerkzeug ist Windows Task Manager und auch Ja PrintWorker :: ~ PrintWorker() wird aufgerufen und ich bekomme es nicht ich mache mein Thread-Objekt privat und setzen 'QObject :: connect (_printThread, & QThread :: zerstört, dies , & NewService :: onPrintDone); 'jetzt sehe ich' QObject (0x2647bb040f0) 'über' qDebug() << _printThread; '!! So wird es nicht gelöscht – IMAN4K

+0

Löschen von '_printThread' wird die Zeigeradresse nicht ändern, es kann noch' QObject (0x2647bb040f0) 'angezeigt werden, selbst wenn gelöscht.OnPrintDone kann auch aufgerufen werden, bevor "QThread" tatsächlich durch den "deleteLater" -Mechanismus gelöscht wird. Schließlich zeigt der Task-Manager die Speichernutzung Ihrer App an, die beim Löschen eines Objekts nicht unbedingt schrumpft. Sie müssen ein Lecksuchgerät verwenden. – jpo38

0

Wenn Sie QThread::quit() aufrufen, beenden Sie den EventLoop in diesem Thread aktiv. A QObject::deleteLater() für Objekte in diesem Thread möglicherweise nicht mehr ausgeführt werden (obwohl sie auf QThread::finished()-Signal angeben, der später löschen Slot wird weiterhin aufgerufen).

Ich persönlich würde nur die Verbindung mit dem finished() Signal einrichten oder legen Sie das Eltern des Worker-Objekts, um den Thread selbst, dann muss Qt tatsächlich das Objekt entfernen.

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