Qt内存管理机制
Qt使用对象父子关系进行内存管理。在创建类的对象时,为对象指定父对象指针。当父对象在某一时刻被销毁释放时,父对象会先遍历其所有的子对象,并逐个将子对象销毁释放。
Qt内存管理代码示例
QLabel *label = new QLabel;
这里是自己在源码中新建的label控件,没有指定父对象,需要自己手动释放内存,不释放会有内存泄漏。
QLabel *label = new QLabel();
这里是自己在源码中新建的label控件,执行了QLabel的构造函数,没有指定父对象,需要自己手动释放内存,不释放会有内存泄漏。
QLabel *label = new QLabel;
label->setParent(this);
设定了父对象,不仅可以显示在父窗口,还可以自动帮助释放内存
QStandardItemModel *itemModel = new QStandardItemModel;
ui.tableView->setModel(itemModel);
这里只是设置了model,ui控件不是model的父对象,无法帮助itemModel释放内存;
QStandardItem *item = new QStandardItem;
itemModel->setItem(1,item);
itemModel->clear();
这里model做了clear操作,会帮助释放model下item占用的内存,没有释放model的内存;
MyWidget *myWidget = new MyWidget;
自己创建的界面也要自己手动释放内存空间;
Qt定位到内存泄漏位置的方法
Visual Leak Detector(VLD)是一款用于Visual C++的免费的内存泄露检测工具。使用VLD可以检测到内存泄漏的位置。VLD支持MSVC编译器,不支持MingGW编译器。VLD的使用方法:
从这里下载,下载后可以看到VLD的include文件,lib文件,不需要从网上下载exe了。
VLD内存泄漏检测编程文件,包含头文件,库文件,配置文件
使用方法
在项目文件内,添加相应的include文件和lib文件,具体步骤不再详解。
1.在头文件内添加
#include "vld.h"
2.在生成的exe文件同级目录下放置vld.ini
vld.ini是VLD的配置文本,默认读取的是安装目录下的vld.ini 文件,当exe所在目录下也有vld.ini文件时会优先读取这份配置。
vld.ini参数设置说明
默认读取的是安装目录下的vld.ini 文件,当exe所在目录下也有vld.ini文件时会优先读取这份配置。
VLD:选择VLD的打开与关闭。在Debug模式下运行,关闭以后会有一行
VLD关闭的提示信息。默认为 on。
AggregateDuplicates:设置为 yes 时,相同地方产生内存泄漏只输
出一次,但是会统计发生的次数。默认是 no 。
MaxDataDump:输出的dump数据个数,默认为 256。
MaxTraceFrames:输出的调用栈的层数。默认是 64。
ReportEncoding :report 文件的编码格式,可选有
ascii, unicode,默认是 ascii 。
ReportFile :report 文件的路径。默认是
“.\memory_leak_report.txt”
ReportTo :可选有 debugger, file, both,debugger
表示输出到 debug模式下的输出窗口;file 表示只输出到文件中;
both顾名思义,全都都输出。默认是 debugger 。
打开exe,操作结束以后,关闭exe,可以看到VLD的报告,报告中包含了几个内容:
【Block X at …: Y bytes】:第X个块(new)泄漏了Y个字节;
【Call Stack】泄漏内存的堆栈信息,对应的行便是具体的代码位置;
【Data】泄漏内存的数据信息;
【Visual Leak Detector detected X memory leak (Y bytes).】总共 X 处泄漏,共泄漏字节数 Y 字节;
一些遇到的问题及解决方案
出现call stack(TID)后面无函数定位,比如:
只需要修改ini文件中ReportEncoding = ascii,ascii为unicode即可,再次执行程序后便可以看到源码定位泄漏位置;
要在release模式下使用VLD,必须在头文件vld.h之前预定于宏(参考 VLD Issues 46)
#define VLD_FORCE_ENABLE
#include "vld.h"