简单的qlabel::settext造成的内存泄漏??

失散糖 2018-10-24 10:12:01
项目中的代码有内存泄漏的嫌疑,最终定位到了qlabel::settext函数,我用这个函数给文本标签中赋值带有html标记的彩色文字,例如
u8"<font color=black>连接</font>"
u8"<font color=red>未连接</font>"
这样的。

为了确认这个函数会不会引发内存泄漏,我在arm-linux的开发板上试验了几个版本的qt:4.8.7,5.6.2,5.8.0,5.9.1,内容就是用qlabel弄出个10乘20的方阵,然后在1秒定时里,对每个qlabel标签,用3个随机数指定一个颜色,用那个颜色写字,看看程序占用内存是不是在增加。

试验代码如下:

settext_test.h:
#ifndef SETTEXT_TEST_H
#define SETTEXT_TEST_H

#include <QtWidgets/QLabel>

class settext_test : public QWidget
{
Q_OBJECT
public:
settext_test();
public slots:
void rand_update();

private:
QLabel *label[20][10];
};

#endif // SETTEXT_TEST_H


settext_test.cc:
// test settext

#include <stdlib.h>
#include <time.h>

#include <QtWidgets/QApplication>
#include <QtCore/QTimer>
#include "settext_test.h"

settext_test::settext_test()
{
this->resize (800, 480);
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 10; x++)
{
label[y][x] = new QLabel(this);
label[y][x]->resize (79, 19);
label[y][x]->move (80 * x, 24 * y);
}
}
}

void settext_test::rand_update()
{
char text[64] = "";

for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 10; x++)
{
unsigned char r = rand () & 0xFF;
unsigned char g = rand () & 0xFF;
unsigned char b = rand () & 0xFF;
snprintf (text, 64, "<font color=#%02X%02X%02X>%02X%02X%02X</font>",
r, g, b, r, g, b);
label[y][x]->setText (text);
}
}
}

int main(int argc, char *argv[])
{
srand (time (0));
QApplication a(argc, argv);

settext_test widget;
#ifdef linux
widget.setWindowFlags(Qt::FramelessWindowHint); //无边框
#endif

widget.show ();

QTimer t;
t.connect (&t, SIGNAL(timeout()), &widget, SLOT(rand_update()));
t.start (1000);

return QApplication::exec();
}

// end of file


windows下截屏的效果如下:


现在确认,在linux下4.8.7,5.6.2,5.8.0,用top命令发现内存持续增加,5.9.1正常。
在windows下,将定时器的周期从1000毫秒改成20毫秒,使用5.6.2版本跑了1个小时,内存吃了700多兆……
因此我怀疑5.9之前的版本都有内存泄漏,而5.9或者是修复了这个问题,或者是修改引擎而使这个问题消失了。

我想知道的是,在5.9之前,这个问题就没有人遇到过吗?我如果不想升级到5.9,那么该如何修改才能避免内存泄漏?还是说建议动大刀,把之前的项目都跟着改成5.9呢,毕竟5.6和5.9属于LTS版本,我们使用的5.8.0已经过了支持期了。。
...全文
1107 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
失散糖 2018-10-30
  • 打赏
  • 举报
回复
#8这个方法好邪道呀,在装置上用版本5.8的测试代码跑了20多个小时没有问题。 上周五已经让现场把qt换成版本5.9了,也没问题。
  • 打赏
  • 举报
回复 1
引用 7 楼 sugar13 的回复:
[quote=引用 6 楼 dcmilan 的回复:] 目前查到的位置在QTextDocument::setHtml这里 你一定要用richtext么?你把richtext关了就没泄漏了 我已经测试过了
这是为了在标签中用彩色显示文字,比如显示“连接”时使用黑色,显示“未连接”时使用红色。 假如我要把richtext关了,能够实现在一个标签中实现多种颜色吗?我试过styleSheet,不过这东西很不友好呀,而且貌似没法在一个标签中同时显示多种颜色的文字,比如一段稍长的黑色文字中,夹杂着若干个红色文字这种。[/quote] 我简单测试了下,加两行代码

            snprintf(text, 64, "<font color=#%02X%02X%02X>%02X%02X%02X</font>",
                      r, g, b, r, g, b);
            label[y][x]->setTextFormat(Qt::PlainText);
            label[y][x]->setTextFormat(Qt::RichText);
            label[y][x]->setText(text);
你再长时间测试一下吧。我看效果还行
失散糖 2018-10-29
  • 打赏
  • 举报
回复
引用 6 楼 dcmilan 的回复:
目前查到的位置在QTextDocument::setHtml这里 你一定要用richtext么?你把richtext关了就没泄漏了 我已经测试过了
这是为了在标签中用彩色显示文字,比如显示“连接”时使用黑色,显示“未连接”时使用红色。 假如我要把richtext关了,能够实现在一个标签中实现多种颜色吗?我试过styleSheet,不过这东西很不友好呀,而且貌似没法在一个标签中同时显示多种颜色的文字,比如一段稍长的黑色文字中,夹杂着若干个红色文字这种。
  • 打赏
  • 举报
回复
目前查到的位置在QTextDocument::setHtml这里 你一定要用richtext么?你把richtext关了就没泄漏了 我已经测试过了
失散糖 2018-10-25
  • 打赏
  • 举报
回复
引用 3 楼 dext 的回复:
代码没问题 但是我可能不会用snprintf 而用 QString().arg(),新版本可能有修复 你可以看看Qt 5.9.x 的changelog.
1楼代码的目的是试验qlabel::settext函数的问题,用snprintf还是用QString::arg与主题无关。 不过我还是想知道,QString::arg适合arm里使用吗?毕竟qt给我的感觉就是不停new东西,然后偷偷摸摸delete了,QString::arg这个函数的仅仅一次调用肯定也有大量的new和delete吧? 所以我更倾向于能不去依赖qt的部分就不用qt,而是去用C标准库
懒懒的吉他手 2018-10-25
  • 打赏
  • 举报
回复
在Qt4版本时代就有你这样的情况出现,而Qt的回答是“这是一次性的小泄漏”。内核代码就有问题

失散糖 2018-10-24
  • 打赏
  • 举报
回复
引用 1 楼 u010111033 的回复:
搞了个二维数组的label,你的label给他绑定widget作为父控件,就不会有内存泄露了。或者你用智能指针来操作,你出问题最大的原因是,c的风格代码在Qt里太多,但是没用好。
label[y][x] = new QLabel(this); 构造函数里创建这个标签数组的时候,就是把widget作为每个标签的父控件的。 我没有用“智能指针”。风格什么的,在代码的什么地方没用好? 顺便强调一下,版本5.9.1下,没有问题。
Little柯南 2018-10-24
  • 打赏
  • 举报
回复
搞了个二维数组的label,你的label给他绑定widget作为父控件,就不会有内存泄露了。或者你用智能指针来操作,你出问题最大的原因是,c的风格代码在Qt里太多,但是没用好。
dext 2018-10-24
  • 打赏
  • 举报
回复
代码没问题 但是我可能不会用snprintf 而用 QString().arg(),新版本可能有修复 你可以看看Qt 5.9.x 的changelog.
Qt智能指针--QScopedPointer ⽂章⽬录 概述 前⼀篇⽂章我们详细的介绍了的⽤法,那么,这⾥继续总结Qt的另⼀个智能指针QScopedPointer的⽤法。 QScopedPointer和C++中的智能指针std::unique_ptr其概念是⼀样的,它包装了new操作符在堆上分配的动态对象,能够保证动态创建 的对象在任何时候都可以被正确地删除。但它有更严格的所有权,并且不能转让,⼀旦获取了对象的管理权,你就⽆法再从它那⾥取回来。 也就是说,只要出了作⽤域,指针就会被⾃动删除,因为它的拷贝构造和赋值操作都是私有的,与QObject及其派⽣类风格相同。 QScopedPointer ⾸先我们来看⼀个官⽅⽰例: 没有使⽤智能指针: void myFunction(bool useSubClass) { MyClass *p = useSubClass ? new MyClass() : new MySubClass; QIODevice *device = handsOverOwnership(); if (m_value > 3) { delete p; delete device; return; } try { process(device); } catch (...) { delete p; delete device; throw; } delete p; delete device; } 上⾯的写法,稍有不慎就会导致内存泄露,但是如果使⽤智能指针,就会变得很简单了: void myFunction(bool useSubClass) { QScopedPointer p(useSubClass ? new MyClass() : new MySubClass); QScopedPointer device(handsOverOwnership()); if (m_value > 3) return; process(device); } 注意:因为拷贝构造和赋值操作私有的,所以不能⽤作容器的元素。 const 限制 C ++指针的const限定也可以⽤QScopedPointer表⽰: const QWidget *const p = new QWidget(); // 等同于: const QScopedPointer p(new QWidget()); QWidget *const p = new QWidget(); // 等同于: const QScopedPointer p(new QWidget()); const QWidget *p = new QWidget(); // 等同于: QScopedPointer p(new QWidget()); 考虑⼀种情况 上⾯说到,使⽤QScopedPointer智能指针动态创建的对象,⼀旦出了作⽤域就会 被⾃动释放并置空,那么如果需要函数返回值怎么办 呢? ⽐如下⾯这种情况: QLabel * createLabel() { QScopedPointer<QLabel> pLabel(new QLabel()); // return pLabel.data(); //invalid return pLabel.take(); //valid } int main(int argc, char *argv[]) { QApplication a(argc, argv); QScopedPointer<QLabel> p1(createLabel()); p1->setText("hello"); p1->show(); return a.exec(); } 注意,我们在createLabel()函数中创建label对象并返回时,不能使⽤data(),⽽要使⽤take(); 因为 T *QScopedPointer::data() const返回指向对象的常量指针,QScopedPointer仍拥有对象所有权。 所以通过data()返回过后就被 ⾃动删除了,从⽽导致mian函数中的p1变成了野指针,程序崩溃。 ⽽使⽤T *QScopedPointer::take()也是返回对象指针,但QScopedPointer不再拥有对象所有权,⽽是转移到调⽤这个函数的caller,同 时QScopePointer对象指针置为NULL。 另外还有⼀个函数要注意。 void QScopedPointer::reset(T *other = Q_NULLPTR):delete⽬前指向的对象,调⽤其析构函数,将指针指向另⼀个对象other,所有 权转移到

16,175

社区成员

发帖
与我相关
我的任务
社区描述
Qt 是一个跨平台应用程序框架。通过使用 Qt,您可以一次性开发应用程序和用户界面,然后将其部署到多个桌面和嵌入式操作系统,而无需重复编写源代码。
社区管理员
  • Qt
  • 亭台六七座
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧