转载自:http://blog.sina.com.cn/s/blog_63578f140100wrw2.html
Qt: 释放窗口资源 1. 对于使用指针,使用new创建的窗口,当然可以使用delete显示的释放其占用的资源: Widget *w = new Widget(); delete w; 2. 对于使用指针,使用new创建的窗口,还可以使用QWidget::setAttribute方法来当窗口关闭后自动释放其占用的资源,而不用户显示的去调用delete释放,此方法当然也会调用窗口的析构函数: Widget *w = new Widget(); w->setAttribute(Qt::WA_DeleteOnClose); 这可以用于非模态对话框,因为非模态对话框如果是用指针形式创建,但是再接着delete的话,窗口就没了,如果不使用delete释放窗口占用的资源,又会赞成泄漏。如果使用普通变量创建,同样的也因为变量作用域马上就结束而窗口也没了,另一种方法就是使用多线程,不过这个的代价大了点。所以这种技术在创建非模态对话框上是非常典型的运用。 测试方式:在Widget中分配大量的内存,显示与关闭多个此类窗口,看看任务管理器里此程序的内存变化情况,是否真正的释放了占用的内存(当然释放了)。在C++中使用new分配内存时,如array = new double[length],此时,给array的内存实际上并没有真正的分配,必须等到第一次使用这些内存后才会真正地为其分配物理内存,如:memset(array, 1, length * sizeof(double)) 3. 窗口的内存管理交给父Widget: Widget *w = new Widget(parent); 但这时,如果父Widget不结束,这个窗口的资源一直会占用着。 至于使用哪种技术来释放窗口的资源,要看具体的运用时,哪种方式更合适。 |
使用QT进行内存管理
Garbage Collection through the Back Door
通过后门垃圾回收
Highly typed programming languages demand explicit (or at least implicit) creation of objects mentioning their types. They differ in how the objects are deleted: there are two approaches - direct deletion by the program or garbage collection by the language.
高级类型的语言要求对象创建时明确的(或者至少是隐式的)声明他们的类型。他们可以通过对象是如何销毁的来区别:有两种方法——通过程序直接销毁或者通过语言的垃圾回收机制。
Explicitly deleting languages (eg. C++, Pascal) demand that the user knows when it is best to get rid of a dynamically created object. Garbage collected languages (eg. Java, SmallTalk) try to find out when an object is no longer used and automatically reclaim the memory.
明确的删除的语言(如,C++,Pascal)要求用户知道什么时候最好避免动态创建的对象。垃圾回收的语言(如java,Smaltalk)尝试找出什么时候一个对象不再被使用并自动的回收那部分的内存。
Explicit deletion has the nice property that the programmer is in full control over the programs ressources - the amount of memory used and the amount and timing of CPU cycles spent on managing these ressources.
明确的删除的好处那就是程序员可以完全控制程序或者资源——使用的内存的大小和管理这些资源花费的cpu周期的大小和数量。
Garbage Collection on the other hand takes a lot of responsibility off the programmer by keeping track on object references inside the system and freeing memory as needed.
另一方面垃圾回收通过在系统内部维持对象的属性的轨迹并且在必要时释放内存来分担程序员的一部分的职责
默认的C++的内存处理
C++ is a language that demands that the user deletes objects explicitly. There are three important strategies on how to handle this:
C++是一种要求用户显式的删除对象的语言。在如何处理方面有三种重要的策略:
Let the creating object delete its child objects.
Let the last object to handle an object delete it.
Don't care about memory and forget about it.
让创建的对象删除它的子对象。
让最后的对象来控制一个对象来删除它。
不关心内存并且忘了有这件事。
最后的策略被称为内存泄露并且常常被认为是一个‘bug’
The real problem with C++ is to find out which of the first two strategies is right and how to implement it. There are some cases in which the creating object is deleted much earlier than the child object and in which it is hard to find out which is the last object to handle it.
C++中的真正的问题是找出前两种策略的哪个是正确的并且如何实现它。在一些情况中创建的对象比子对象删除的早的多并且很难找出哪个是最后的对象来处理它
Default Qt Memory Handling
默认的QT内存处理
Qt maintains hierarchies of objects. For widgets (visible elements) these hierarchies represent the stacking order of the widgets themselves, for non-widgets they merely express "ownership" of objects. Qt deletes child objects together with their parent object. While this takes care of 90% of memory handling problems it also brings some challenges and leaves a few aspects open.
Qt维护了对象的分类。对widget(可视化元件)这些层次表现在widgets的压栈顺序,对非widget的他们很少表现出对象的归属。Qt把子对象和他们的父对象一起删除。这样能够处理90%的内存处理问题同时它也带来了一些机会并且一些方面的敞开。
Qpointer是一个模版类,它能够监控动态对象并且在对象被删除时更新,否则它和一般的指针的表现几乎是一样的。
QDate *mydate=new QDate(QDate::currentDate());
QPointer<QDate> mypointer=mydata;
mydate->year();
mypointer->year(); // -> 2005
在删了原对象之后他就开始有不同的表现了
delete mydate;
else printf("dangling pointer");
// -> "dangling pointer"
else printf("dangling pointer");
// -> clean pointer
Qt中的cleanup句柄是自动垃圾回收中走的更远的一步。它能够注册多个的子对象并且在他被删除的同时删除它们。它同样可以自动的发现任何他的注册的对象被提前删除并且从他的表中删除。
这个类可以在不在同一层次的对象因为一个特殊的事件(如当一个按钮被按下或者当另一个窗口被关闭的时候,几个顶层的窗口需要被关闭)被删除的任何时候使用.
//instantiate handler
QObjectCleanupHandler *cleaner=new QObjectCleanupHandler;
//create some windows
QPushButton *w;
w=new QPushButton("Remove Me");
w->show();
//register first button
cleaner->add(w);
//if first button is pressed, it removes itself
connect(w,SIGNAL(clicked()),w,SLOT(deleteLater()));
//create second button with no function
w=new QPushButton("Nothing");
cleaner->add(w);
w->show();
//create third button to delete all
w=new QPushButton("Remove All");
cleaner->add(w);
connect(w,SIGNAL(clicked()),cleaner,SLOT(deleteLater()));
w->show();
在上面的三个包含了一个简单的窗体代码被创建。如果第一个按钮("Remove Me")被按下的时候,它将会删除自己(经由"deleteLater"槽)并且cleanup句柄将自动的把它从他的表中删除。如果第三个按钮("Remove All")被按下的时候,它将删除cleanup句柄,这将依次删除所有还是开着的按钮。
用Qt进行垃圾回收
Sometimes objects are handed around to different other objects which all jointly own this object - so it is hard to determine when to delete this object. Fortunately with Qt it is possible to emulate garbage collection for child and parent classes that are derived from QObject.
有时候对象被传递给了不同的拥有这个对象的其它对象,所以很难决定什么时候删除这个对象。幸运的是使用Qt,模拟为源自QObject的父子类垃圾回收将是可能的。
There are several approaches to garbage collection. The easiest way is to implement instances counters, or one could store all owning objects. The garbage collection could be added to the class itself or handled by an outside object. Several of these methods will be developed below.
有几种方法可以进行垃圾回收。最简单的方法是实现实例计数器,或者一个可以存放所拥有的对象。垃圾回收可以被加到一个类自身中或者被一个外部的对象处理。下面是这些方法的实现的几个例子。
Instance Counting
实例计数
Instance counting is the easiest way of implementing garbage collection. For each reference made to the object the counter is increased, for each release it is decreased:
实例计数是实现垃圾回收的最简单的方法。对每个声明,将会使该对象的计数器增加,每个释放将使其减小。
class CountedObject
{
};
在对象他得到所有权时,每个拥有该对象的对象需要调用attach,并且在释放的时候要调用detach。到目前为止这种方法没有使用qt的先进性,更为自动的方法应该是这样的:
class CountedObject:public QObject
{
};
在这段代码中detach()方法将会在所拥有的对象被删除的时候自动地被调用。不幸的是没有考虑到一个所拥有的对象会意外的调两次的attach()。
Owner Collection
所有者回收
A more intelligent approach is to not only remember how many objects own this object, but which ones.
更为智能的方法是不仅仅记住多少个对象拥有这个对象,而是哪个对象
class CountedObject:public QObject
{
};
这段代码最终能够在因为多次调用attach或者detach所导致的错误中保护自己了。不幸的是它不能够在根本没有调用attach的错误中保护自己,因为他没有办法强迫C++告诉类有多少指针存在指向给定的对象的指针。
一般的方法
It is also possible to factor this code out into its own class, so that multiple objects can be handled by the same garbage collector instance and be delete simultaniously after the last parent was deleted.
同样也可以将这段代码提取出来放入它自己的类中,以便多个对象能够通过相同的垃圾回收实例来处理,并且通过最后的父对象被删除的刺激而删除。
qgarbagecollector.cpp
qgarbagecollector.h
上面的代码链接能够在一个独立的垃圾回收的对象中处理多个子对象。当垃圾回收者或者最后的父对象被删除时,所有的子对象被同时删除。垃圾回收的指针不需要装载,实例在完成它的任务之后会删除它自己。