QQt对象树系统及内存自动回收机制
Qt对象树
Qt中QObject类是所有Qt对象的基类。
Qt通过对象树管理QObject类及其子类。
创建QObject对象时(不论是一在个堆上还是栈上),可以指定一个父对象,父对象会将这个新的子对象添加到children列表中(可以用findchild和findchildren查看)。当父对象析构时,会将children列表中的对象析构(但是两者并没有明确的先后顺序),从而在一定程度上简化了内存管理。
下面看一个例子。myButton是继承自QPushButton的一个子类,并对其析构函数修改,添加打印信息。
#include "mybutton.h"myButton::myButton(QWidget *parent) : QPushButton(parent)
{setText("myButton");
}myButton::~myButton()
{qDebug() << "delete myButton";
}
helloworld继承自QWidget,在helloworld中new一个myButton对象,并不在析构函数中delete它,在析构函数修改,添加打印信息。
#include "helloworld.h"helloworld::helloworld(QWidget *parent): QWidget(parent)
{resize(800,600);myButton *btn = new myButton(this);
}helloworld::~helloworld()
{qDebug() << "delete helloworld";
}
运行后如下,将主窗体关闭后查看后台信息。
我们并没有对new出来的btn做delete,但是同样被析构了,这就是Qt对象树的作用。
问题一:
而我们如果把main.cpp中的
helloworld w;
改为
helloworld *w = new helloworld;
运行后关闭主窗口,在后台没有析构的打印信息。
这是因为,对于在对上面创建的w,如果没有delete,则关闭按钮只是将窗体隐藏。这个对象仍然存在,可以重新调用show再次显示。
#include "helloworld.h"
#include <QApplication> int main(int argc, char *argv[])
{QApplication a(argc, argv);//堆上验证对象树helloworld *w = new helloworld();w->show();w->close();Sleep(1000);w->show();return a.exec();
}
上述代码的效果是主窗体显示1s后,关闭,1s后重新打开。(Sleep需要添加Windows.h头文件)
我们可以做个实验:在helloworld.cpp中不断创建局部变量(栈上)。myWidget是继承QWidget的子类。
myButton *btn=new myButton(this);connect(btn,&myButton::clicked,[=](){//在堆上创建 myWidget *widget = new myWidget();widget->resize(300,200);myButton *btn = new myButton(widget);widget->show();widget->close(); });int i=10000;while (i--) {btn->click();}
这段代码就是运行后不断点击按钮btn在栈上创建一个widget和button,并关闭widget。运行程序后打开任务管理器,查看内存使用情况,会随着btn按钮调用,内存在不断增加(内存泄漏),且后台没有调用myWidget和myButton的析构函数打印信息。
而如果换成如下代码:
myButton *btn=new myButton(this);connect(btn,&myButton::clicked,[=](){//在栈上创建 myWidget widget;widget.resize(300,200);myButton *btn = new myButton(&widget);widget.show();widget.close(); });int i=10000;while (i--) {btn->click();}
则内存不会增加,且每次widget.close();都会在后台打印析构信息。
同样道理,对于创建全局变量,如果创建在堆上,则应该指定父对象,或者在调用类的析构函数中delete实例化对象,或者设置
Qt::WA_DeleteOnClose属性,在窗口关闭后主动delete对象。
问题二:
对于在栈上创建的对象。
对于局部变量
//栈上创建对象的对象树问题myWidget widget;widget.resize(300,200);myButton btn;btn.setParent(&widget);widget.show();
运行后会一闪而过,并且widget和button都析构了(在后台有打印信息)。
为了能清楚显示,创建两个全局变量
myWidget mywidget;myButton mybutton;
然后添加代码:
//栈上创建局部对象的对象树问题mywidget.resize(300,200);mybutton.setParent(&mywidget);mywidget.show();
关闭mywidget窗口后没有反应,是因为该变量是全局变量,需要程序结束才能销毁。关闭主窗体,则析构这两个变量。
但是如果将两个变量的声明修改顺序:
myButton mybutton;myWidget mywidget;
则会报错。这是因为C++的局部变量和全局变量释放顺序为:局部变量优先于全局变量,同级别下,先声明的后释放。
所以mywidget先释放,并将children下的mybutton释放;然后再释放mybutton时会报无法访问内存地址的错误。
总结:
在栈上创建对象,可以指定父对象也可以不指定,但是指定的父对象必须比该对象本身早;
在堆上创建对象,对于局部变量,则应指定其父对象,对于全局变量,应指定其父对象或在析构函数中进行delete回收,否则无法对该对象回收,造成内存泄漏。
QQt对象树系统及内存自动回收机制相关推荐
- QT对象树、信号和槽机制
文章目录 一 .对象树是什么? 二.信号和槽的基本概念 2.1 信号 2.2 槽 2.3 松散耦合 2.4 特点 三.示例 总结 一 .对象树是什么? 对象树是由父类和若干子类对象组成,而子类也可以由 ...
- iOS 内存管理机制与原理
内存分区 内存一般分为五大区:栈区.堆区.常量区.全局区.代码区.如图 1.栈区 是由编译器自动分配并释放的,主要用来存储局部变量.函数的参数等,是一块连续的内存区域,遵循先进后出(FILO)原则.一 ...
- Android 内存管理机制
本文主要包括三大部分内容: 内存管理基础:从整个计算机领域简述主要的内存管理技术. Linux的内存管理机制:Android毕竟是基于Linux内核实现的操作系统,因此有必要了解一下Linux的内存管 ...
- python中内存管理机制一共分为多少层_python 内存管理机制
内存管理机制 python中万物皆对象,python的存储问题是对象的存储问题,并且对于每个对象,python会分配一块内存空间去存储它 Python的内存管理机制:引入计数.垃圾回收.内存池机制 ...
- 【Qt教程】1.5 - Qt5内存回收机制-对象树、窗口坐标系
1.Qt内存回收机制 - 对象树 (做了解,懂就可以,示例看视频) 当创建的对象在堆区时,如果指定的父亲是 QObject派生下来的类 或者 QObject子类派生下来的类,可以不用管理释放的操作,对 ...
- java 对象压缩_理解Java对象:要从内存布局及底层机制说起,话说....
前言 大家好,又见面了,今天是JVM专题的第二篇文章,在上一篇文章中我们说了Java的类和对象在JVM中的存储方式,并使用HSDB进行佐证,没有看过上一篇文章的小伙伴可以点这里:< 这篇文章主要 ...
- JVM对象创建与内存分配机制学习总结
对象的创建过程 1.类加载检查 虚拟机遇到一条new指令时(new关键词.对象克隆.对象序列化等),首先会检查这个类是否已被加载.解析和初始化过.如果没有,要先执行相应的类加载过程. 2.分配内存 内 ...
- 6-Qt6对象树及内存管理
把类的对象组织成树形结构,这种树形结构也称为对象树,Qt 使用对象树来管理 QObject 及其子类的对象. 重要:当父对象析构的时候,这个列表中的所有对象也会被自动逐级析构. 如下图树形,当Pare ...
- linux系统内存dump机制介绍(一)--kdump
本文来自 网易云社区 . kdump的原理介绍 按照linux系统的设计哲学,内核只提供dump内存的机制,用户想要dump什么样的内存,dump多少内存是属于策略问题,由用户来决定. 在真实的使用场 ...
最新文章
- 解决python3 UnicodeDecodeError: 'gbk' codec can't decode byte
- C#中Encoding.Unicode与Encoding.UTF8的区别
- I/O复用函数的使用——poll
- Serverless.com CEO首次访华!探讨无服务器技术落地
- System.gc()调用 - 适用的场景
- android SpannableString使用详解
- phpize的作用(资料整理)
- 安装vs2008出现MSI returned error code 1603的错误的解决
- cocosbuilder入门
- ftp主动模式与被动模式
- hackinglab-脚本关10——基情燃烧的岁月
- MiniMap(小地图)插件
- QQ机器人 微信机器人最新可用框架汇总
- 论文的主要观点怎么写?
- codeforces 618 C. Constellation(三角形,三点共线)
- Prompt-Tuning——深度解读一种新的微调范式
- 计算机网络相关论文目录怎么弄,如何给你的标书、论文编页码和目录-论文页码设置...
- php怎么判断qq内置浏览器,如何判断微信内置浏览器(JS PHP)
- springboot微信公众号发送模板消息
- 友盟多渠道打包+混淆+腾讯云直播的推/拉流