QImage 和 valgrind;内存泄漏

4

我对以下代码有问题:

#include <QtGui/QImage>

int main(int argc, char* argv[]) {
  QImage qimage(100, 100, QImage::Format_ARGB32);
  qimage.fill(Qt::white);
  qimage.save("test.png", "PNG", 70);

  return 0;
}

编译方式如下:

gcc -I/usr/include/qt4 test.cpp -lQtGui

代码生成了一张正确的图片。然而,当我使用valgrind检查时:
valgrind --leak-check=full ./a.out

它会生成一系列失踪的块,例如下面这个:

==5974== 158 (56 direct, 102 indirect) bytes in 1 blocks are definitely lost in loss record 54 of 79
==5974==    at 0x402B9B4: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5974==    by 0x4E4E427: QLibraryPrivate::findOrCreate(QString const&, QString const&) (qlibrary.cpp:437)
==5974==    by 0x4E4E721: QLibrary::setFileNameAndVersion(QString const&, QString const&) (qlibrary.cpp:1110)
==5974==    by 0x56290DF: ???

或者是这个:

==5974== 396 (56 direct, 340 indirect) bytes in 1 blocks are definitely lost in loss record 61 of 79
==5974==    at 0x402B9B4: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5974==    by 0x4E4E427: QLibraryPrivate::findOrCreate(QString const&, QString const&) (qlibrary.cpp:437)
==5974==    by 0x4E44FB6: QFactoryLoader::updateDir(QString const&, QSettings&) (qfactoryloader.cpp:145)
==5974==    by 0x56F9E67: ???

我能帮您进行翻译。以下是您需要翻译的内容:

我就不给你贴完整的日志了,你可以在家里执行相同的操作 :)

我尝试理解,并且它们似乎存在于我在 QImageWriter 的源代码中找到的以下几行中:

QFactoryLoader *l = loader();
QStringList keys = l->keys();

我认为当您首次尝试生成PNG图像时,它会构建一个每次构建PNG图像时都会重复使用的东西,并且该内存永远不会被释放。 QFactoryLoader的析构函数似乎知道如何清理这些内容,我很想亲自执行delete l;,但由于QFactoryLoader对于Qt的实现是私有的,因此没有办法调用它。
有人可能会认为这不是真正的内存泄漏,因为每个图像格式只有一个键,但在我看来,正确的做法应该是在退出之前能够清除所有内容。
因此我的问题是:有没有办法做到这一点?

你不必为这种问题烦恼,因为Qt有系统来释放所有未使用的内存。你在寻找根本不存在的问题。当销毁QImage对象时,Qt将释放这些内存。不知道为什么Valgrind没有看到这一点。 - Blood
如果在任何较大的基于Qt的项目上运行Valgrind,它将会发现数百个可能的内存泄漏。我不知道这些是否都是真正的内存泄漏,或者Valgrind是否只是被Qt内部大量使用指针所搞混了。然而,正如已经提到的,我不会过于担心这个问题。 - scai
2个回答

2

Qt的图像I/O功能是基于插件的。当您请求加载png文件的QImage时,PNG库作为QObject被加载一次,直到程序退出才会卸载 - 这就是Valgrind视为内存泄漏的原因。


这就是我感觉它正在进行的方式。这让我想起了某种单例设计模式(用于已加载插件列表),但它们不会对valgrind造成任何问题,对吧? - xoolive
那么难道没有手动清理已加载插件列表的方法吗? - xoolive
不需要,但是你为什么想要呢?它们被设计成应用程序的寿命,并由操作系统清理。 - cmannett85
我的目的是让valgrind保持沉默,当我检查程序的其余部分时不被Qt噪声干扰。我相信一个程序不应该依赖操作系统来清理自己的烂摊子。 - xoolive
我同意这一点,但只是为了整洁而已。这并不是内存泄漏,因为插件运行所需的内存不会超过所需的内存;而且您的操作系统会清理堆栈,它是否也会清理堆分配呢?至于Valgrind,要消除各种输出,请使用抑制文件(http://valgrind.org/docs/manual/manual-core.html#manual-core.suppress)。 - cmannett85

-2
为什么不使用QCoreApplication呢?只有这样QObject GC才会生效,清理工作才能正常进行。Qt内部构建了太多指针,这些指针由主事件循环管理,如果没有它,就会变得非常混乱和破坏性。

1
QObject 子类的销毁与 QCoreApplication 无关。 - cmannett85

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接