简体   繁体   English

如何销毁QPainter对象/摆脱drawText()内存泄漏?

[英]How do I destroy the QPainter object / Get rid of drawText() memory leak?

I'm trying to trim down the memory leaks of a large application. 我正在尝试减少大型应用程序的内存泄漏。 Using valgrind, I also saw many instances of memory leaks when calling the drawText() function of the QPainter class. 使用valgrind,我在调用QPainter类的drawText()函数时也看到了许多内存泄漏实例。 It could be a Qt bug according to some sources that I've read, but I was thinking maybe I could get rid of it by destroying the QPainter object just as the documentation has said -> "Remember to destroy the QPainter object after drawing." 根据我读过的一些消息来源,它可能是一个Qt bug,但我想也许我可以通过破坏QPainter对象来解决它,正如文档所说 - >“记住在绘制后销毁QPainter对象。 “

  • What is the right way of doing that? 这样做的正确方法是什么?

Here's one instance of valgrind log where drawText() causes a leak: 这是valgrind日志的一个实例,其中drawText()导致泄漏:

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)

If you create the QPainter object on the stack (that is, not using new ), as is mentioned in the documentation: 如果在堆栈上创建QPainter对象(即不使用new ),则如文档中所述:

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

Then the QPainter object will be destroyed when it falls out of scope (in the example above: at the end of the function). 然后QPainter对象在超出范围时将被销毁(在上面的例子中:在函数的末尾)。 The reason the documentation mentions that you need to be careful to delete the QPainter object, is because Qt will not do so itself, which is a bit different from a lot of Qt widget management. 文档提到您需要小心删除QPainter对象的原因是因为Qt本身不会这样做,这与许多Qt小部件管理有点不同。

So, say you allocated this object dynamically instead: 所以,假设你动态分配了这个对象:

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 is telling you that you are in charge of cleaning up the QPainter object, which in our example, is done using the delete command. Qt告诉您,您负责清理QPainter对象,在我们的示例中,使用delete命令完成。 However, if you're using this approach, you might consider putting it in a smart pointer, ie: boost::scoped_ptr<QPainter> painter = new QPainter(this); 但是,如果你使用这种方法,你可以考虑把它放在智能指针中,即: 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");
}

Now, as for the right way to do it. 现在,至于正确的方式。 It depends, how often would you have to create QPainter objects if you created them locally, like in the example? 这取决于,如果您在本地创建QPainter对象,您需要多久创建一次QPainter对象,如示例中所示? If this causes overhead, consider creating the QPainter as a member variable, and reusing it. 如果这会导致开销,请考虑将QPainter创建为成员变量,然后重复使用它。 (Though, if you're concerned about speed: "optimizing early is never a good idea" is something that should be committed to heart). (但是,如果你担心速度:“早期优化永远不是一个好主意”是应该致力于内心的事情)。

If you allocate memory dynamically using new , remember that you are in charge of deleting it as well. 如果使用new动态分配内存,请记住您也负责删除它。 If you just create it on the stack like in the top most example, you shouldn't have to worry, as it will be destroyed whenever it exits the scope where it was created. 如果您只是在堆栈中创建它,就像在最顶层的示例中一样,您不必担心,因为它会在退出创建它的范围时被销毁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM