1

大規模なアプリケーションのメモリ リークを削減しようとしています。valgrind を使用すると、クラスのdrawText()関数を呼び出すときにメモリ リークの多くのインスタンスも確認されました。私が読んだいくつかの情報源によるQPainterと、それはバグである可能性がありますが、ドキュメントにあるように、オブジェクトを破棄することでそれを取り除くことができるのではないかと考えていました->「描画後にオブジェクトを破棄することを忘れないでください。」QtQPainterQPainter

  • それを行う正しい方法は何ですか?

drawText()リークの原因となるvalgrind ログの 1 つのインスタンスを次に示します。

127971 ==00:00:05:31.916 24132== 68,594 (768 direct, 67,826 indirect) bytes in 2 blocks     are definitely lost in loss record 4,979 of 4,982
127972 ==00:00:05:31.916 24132==    at 0x4C2683D: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
127973 ==00:00:05:31.916 24132==    by 0x81861FF: ft_mem_qalloc (in /usr/lib64/libfreetype.so.6.6.2)
127974 ==00:00:05:31.916 24132==    by 0x8186242: ft_mem_alloc (in /usr/lib64/libfreetype.so.6.6.2)
127975 ==00:00:05:31.916 24132==    by 0x81876BE: FT_New_Library (in  /usr/lib64/libfreetype.so.6.6.2)
127976 ==00:00:05:31.916 24132==    by 0x81819C3: FT_Init_FreeType (in /usr/lib64/libfreetype.so.6.6.2)
127977 ==00:00:05:31.916 24132==    by 0x54E4667: ??? (in /usr/lib64/libQtGui.so.4.7.1)
127978 ==00:00:05:31.916 24132==    by 0x54E4A64:  QFontEngineFT::init(QFontEngine::FaceId, bool, QFontEngineFT::GlyphFormat) (in  /usr/lib64/libQtGui.so.4.7.1)
127979 ==00:00:05:31.916 24132==    by 0x54DE0B5: QFontEngineX11FT::QFontEngineX11FT(_FcPattern*, QFontDef const&, int) (in /usr/lib64/libQtGui.so.4.7.1)
127980 ==00:00:05:31.916 24132==    by 0x542EE80: ??? (in /usr/lib64/libQtGui.so.4.7.1)
127981 ==00:00:05:31.916 24132==    by 0x543721A: QFontDatabase::load(QFontPrivate const*, int) (in /usr/lib64/libQtGui.so.4.7.1)
127982 ==00:00:05:31.916 24132==    by 0x5414D46: QFontPrivate::engineForScript(int) const (in /usr/lib64/libQtGui.so.4.7.1)
127983 ==00:00:05:31.916 24132==    by 0x5429FDD: QFontMetricsF::leading() const (in /usr/lib64/libQtGui.so.4.7.1)
127984 ==00:00:05:31.916 24132==    by 0x534ED45: ??? (in /usr/lib64/libQtGui.so.4.7.1)
127985 ==00:00:05:31.916 24132==    by 0x534FCBD: QPainter::drawText(QRect const&, int, QString const&, QRect*) (in /usr/lib64/libQtGui.so.4.7.1)
127986 ==00:00:05:31.916 24132==    by 0x5863AC: gui::base::Printer::printTitle() (in /home/bed/workspace/tasks/MemProfile/MemoryProfiling/build-pc-debug/src/application-ui)
127987 ==00:00:05:31.916 24132==    by 0x585559: gui::base::Printer::run() (in /home/bed/workspace/tasks/MemProfile/MemoryProfiling/build-pc-debug/src/application-ui)
127988 ==00:00:05:31.916 24132==    by 0x5D49A5D: ??? (in /usr/lib64/libQtCore.so.4.7.1)
127989 ==00:00:05:31.916 24132==    by 0x7620A3E: start_thread (in /lib64/libpthread- 2.11.3.so)
127990 ==00:00:05:31.916 24132==    by 0x738067C: clone (in /lib64/libc-2.11.3.so)
4

1 に答える 1

2

ドキュメントに記載されているように、スタック上に QPainter オブジェクトを作成する (つまり、を使用しないnew) 場合:

void SimpleExampleWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setPen(Qt::blue);
    painter.setFont(QFont("Arial", 30));
    painter.drawText(rect(), Qt::AlignCenter, "Qt");
}

その後、QPainter オブジェクトはスコープ外になると破棄されます (上記の例では、関数の最後)。QPainter オブジェクトを慎重に削除する必要があるとドキュメントに記載されている理由は、Qt 自体がそうしないためです。これは、多くの Qt ウィジェット管理とは少し異なります。

したがって、代わりにこのオブジェクトを動的に割り当てたとします。

void SimpleExampleWidget::paintEvent(QPaintEvent *)
{
    QPainter* painter = new QPainter(this);
    painter->setPen(Qt::blue);
    painter->setFont(QFont("Arial", 30));
    painter->drawText(rect(), Qt::AlignCenter, "Qt");
    // Delete object, since Qt wont do it for you:
    delete painter;
}

Qt は、あなたが QPainter オブジェクトのクリーンアップを担当していることを伝えています。この例では、deleteコマンドを使用して行われます。ただし、このアプローチを使用している場合は、スマート ポインターに配置することを検討してください。boost::scoped_ptr<QPainter> painter = new QPainter(this);

void SimpleExampleWidget::paintEvent(QPaintEvent *)
{
    boost::scoped_ptr<QPainter> painter = new QPainter(this);
    painter->setPen(Qt::blue);
    painter->setFont(QFont("Arial", 30));
    painter->drawText(rect(), Qt::AlignCenter, "Qt");
}

さて、正しいやり方について。例のように、QPainter オブジェクトをローカルで作成した場合、どのくらいの頻度で QPainter オブジェクトを作成する必要があるかによって異なります。これによりオーバーヘッドが発生する場合は、QPainter をメンバー変数として作成し、再利用することを検討してください。(ただし、速度が気になる場合は、「早期に最適化することは決して良い考えではありません」と心に留めておく必要があります)。

を使用してメモリを動的に割り当てる場合は、メモリnewの削除も担当していることに注意してください。一番上の例のようにスタック上に作成するだけであれば、作成されたスコープを出るたびに破棄されるため、心配する必要はありません。

于 2012-03-13T08:11:41.123 に答える