Qhash封装之后内存释放问题,求教~
因为工程需要,对QHash进行封装,封装之后,进行Delete,但是内存并不释放,单独对QHash进行测试,发现没有问题,贴出代码,请教各位大神,看看那是哪里的问题~~~~~~头文件如下:
#ifndef SETTABLE_H
#define SETTABLE_H
#include<QHash>
#include "settings.h"
#include<QHashIterator>
#include<QMutex>
#include"systemlog.h"
#include "gloabletime.h"
class SetTable
{
public:
SetTable();
~SetTable();
//COPY CONSTRUCTURE
SetTable(const SetTable& s);
SetTable& operator = (const SetTable& ); //赋值符重载
bool Add(QString Name ,Settings* Value);
bool Remove(QString Name);
Settings* GetItem(QString Name);
QString GetItemByEquipID(QString EquipID);
QString GetItemByEquipID(QString EquipType,QString EquipAddress);
bool SetItem(QString ClassName,Settings* Value);
bool SetItem(QString ClassName,QString SubClassName,QString OptionName,QString Value );
QHash<QString,Settings*>::const_iterator GetIterator();
void ReleaseResource();
int Count();
private:
QHash<QString,Settings*>*StList;// modify by pointer
};
#endif // SETTABLE_H
构造,析构,copy构造 实现如下:
SetTable::SetTable()
{
this->StList=new QHash<QString,Settings*>();
}
SetTable::~SetTable()
{
this->StList->clear();
this->StList->squeeze();
this->StList->detach();
this->StList->~QHash();
delete this->StList;
StList=NULL;
}
SetTable::SetTable(const SetTable& s)
{
this->StList=new QHash<QString,Settings*>;
* this->StList=*s.StList;
}
SetTable& SetTable::operator =(const SetTable& s)
{
if(this==&s)
{
return *this;
}
else
{
* this->StList=*s.StList;
return *this;
}
}
求指教,求解惑,求答疑~~~~~~~~~~ delete --------------------编程问答-------------------- 每一个元素 都要 delete。不能简单的clear --------------------编程问答--------------------
能delete的都delete了,请版主大大仔细看看呀,帮忙分析下 --------------------编程问答-------------------- delete this->StList;这句为什么不起作用呢 --------------------编程问答--------------------
唉,明白了,刚做了个实验,QT的运行机制有问题,或者是不合理......感觉必须要在某个地方结束某种消息循环后,才会真正释放,不然内存占用一直被占用 --------------------编程问答--------------------
分配到栈上也不释放吗? --------------------编程问答-------------------- 不行啊 --------------------编程问答--------------------
我怎么你觉得简单问题复杂化? 你为什么要new并持有一个QHash的指针,直接用栈对象不行?你看你为了它多写了多少代码。我看了下QHash的实现,它只有一个数据成员:包含指针的一个union,也就是说它只占用4 bytes,你确定你有必要在堆上创建?
另外,我不知道你的Setting指向的对象是谁负责创建?谁负责释放,如果你在外部new出它们,然后存在你的SetTable里面,而你没有负责delete,那就是内存泄露。
还有如果你不是在内存很吃紧的嵌入式环境开发,多用QSharedPointer等一类的智能指针吧,能让你的代码更加简洁。 --------------------编程问答--------------------
1.这个是个配置信息类,是要常驻内存的,所以我想在堆上分配;
2.这个配置信息是一个3个hash嵌套构成的数据结构,实现Item("1").item("2").Value的结构;
3.在new之后,类里是有专门的方法来释放的,不是通过析构,代码如下:
void SetTable::ReleaseResource()
{
QHash<QString,Settings*>::iterator i;
i=StList->begin();
while(i!=StList->end())
{
if(i.value()!=NULL)
{
i.value()->ReleaseResource();
delete i.value();
}
i++;
}
}
4.想尝试用QScopePointer指针,但是现在刚接触,还没理解透,正在学习;
5.现在主要的问题不是内存泄露,而是会随着配置文件的增大,Settable占用的内存也变大,但在生命周期结束后,内存并不降低,比如一开始程序占用8M,用Settable读出配置放至内存,为8.5M,此时释放Settable,内存并不降低到8M --------------------编程问答--------------------
SetTable::SetTable()
{
this->StList=new QHash<QString,Settings*>();
}
SetTable::SetTable(const SetTable& s)
{
this->StList=new QHash<QString,Settings*>;
* this->StList=*s.StList;
}
你构造的时候就new了
而在SetTable又新new一个覆盖构造时候的空间(但块内存没看到你那边释放啊),你确认这样不会内存泄露?? --------------------编程问答--------------------
这是没问题的,这两个都是构造函数。 --------------------编程问答--------------------
是的,这都是构造函数,应该没问题的吧 --------------------编程问答-------------------- 这种内存的问题,没有完整的代码,很难得出什么结论。 --------------------编程问答--------------------
要不要我把相关的代码发给您,您帮忙给看看? --------------------编程问答--------------------
例子我已经做好了,很简单的几个类~~~ --------------------编程问答--------------------
可以发我qq邮箱 --------------------编程问答--------------------
已经发给您了,请您看看,谢谢了,实在是困惑啊,百思不得其解.... --------------------编程问答--------------------
抓狂啊....各种方法都试验了,真不明白QT的内存释放机制..... --------------------编程问答-------------------- if(1)
{
QHash<QString,QHash<QString,QHash<QString,QString> > > Options;
for(int i=0;i<10;i++)
{
QHash<QString,QHash<QString,QString> > Tmp2;
for(int m=0;m<1000;m++)
{
QHash<QString,QString> Tmp1;
Tmp1.insert(QString::number(m),QString::number(m));
Tmp2.insert(QString::number(m),Tmp1);
}
Options.insert(QString::number(i),Tmp2);
}
内存就是不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊,不释放啊 --------------------编程问答-------------------- 如果实在搞不明白,就 坚持使用 new delete 配对的原则。
继承自 QObject 的类 会在 delete 的时候 通知 相应的容器类。所以不明白的话,就完全手动new delete。
你的例子中,每个Hash 中的 Settings* 没有被释放过吧。 --------------------编程问答-------------------- >QHash<QString,Settings*>*StList;// modify by pointer
QHash指向的Settings*都要配合一个delete
你还没delete就呼叫clear
Settings的pointers所指向的resource在还没
delete前就都被你clear掉了
你这样子memory怎么可能会自动释放?
大幅简化memory管理的方法是RAII
强烈建议你把这东西弄懂,你以后就不会
再为了这些琐碎的memory问题伤透脑筋
std::unique_ptr<QHash<QString, std::unique_ptr<Settings> > > StList;
或std::shared_ptr
不支援shared_ptr或unique_ptr,Qt自己也有提供smart pointer
如果你对smart pointer有疑问,可以另外选个帖子发问
楼主大概没读过meyers的effective series?对于要用c++开发案子的人来说
阅读meyers的书会有很大的帮助,如果你还没读过
请快点跑去书店买回来啃,不是走去买,是跑去买
--------------------编程问答-------------------- 至于Qt的memory release机制,是基于parent and children的手法
1 : 你的father,children都是QObject
2 : 你的children必须成为father的children
这样一来,father在死亡的时候,就会把地下的children都杀光
你可以把他想像成资料结构的tree
最上层的node(father)死亡前会把底下的nodes(children)都杀了
如果那些nodes底下有children的话他们也会把那些children都杀了
既然QHash不是QObject,那么他就不会被Qt自动回收
memory没有被回收是你的问题,不是Qt的问题 --------------------编程问答--------------------
是这样的,在一开始的代码中没有将代码贴完全,在类里有一个ReleaseResource的方法用来进行释放,这个还请这位大大看如下说明,或者直接看8楼,
1.这个是个配置信息类,是要常驻内存的,所以我想在堆上分配;
2.这个配置信息是一个3个hash嵌套构成的数据结构,实现Item("1").item("2").Value的结构;
3.在new之后,类里是有专门的方法来释放的,不是通过析构,代码如下:
void SetTable::ReleaseResource()
{
QHash<QString,Settings*>::iterator i;
i=StList->begin();
while(i!=StList->end())
{
if(i.value()!=NULL)
{
i.value()->ReleaseResource();
delete i.value();
}
i++;
}
}
这个Settable的析构,纯粹只是来进行释放自身的资源,在析构前,已经调用了ReleaseResource来进行手工释放; --------------------编程问答--------------------
您说的QT的Parent-Children机制,我看过,也试验过,请您建立一个小工程,在Main.cpp里粘贴这些代码,并执行, if(1)
{
QHash<QString,QHash<QString,QHash<QString,QString> > > Options;
for(int i=0;i<10;i++)
{
QHash<QString,QHash<QString,QString> > Tmp2;
for(int m=0;m<1000;m++)
{
QHash<QString,QString> Tmp1;
Tmp1.insert(QString::number(m),QString::number(m));
Tmp2.insert(QString::number(m),Tmp1);
}
Options.insert(QString::number(i),Tmp2);
}
这些代码只是利用了最基本的QHash类,将其分配到栈上,在其生命周期内,也就是{}之内,他应该是存在的,并进行内存分配的,在{}之外,其生命周期应该结束,进行释放以及回收,这些不都是QT的工作吗,如果QT不能进行自动调用QHash的析构,还请您告诉我怎么释放才能释放掉QHash?难道要显式的去调用~QHash()么?求解惑!~~~ --------------------编程问答--------------------
恩,版主大大,这个确实没有被显式的在析构函数中释放过,因为在8楼还有代码贴的是手工释放的... --------------------编程问答--------------------
不用,你的destructor也不必那么做,直接呼叫delete就好
我测过了,离开scope后memory确实有变小(debug版本)
QHash具体如何处理记忆体的我也不清楚,不排除底层用了pool来管理memory的可能性
你某个地方忘了呼叫ReleaseResource?
如果是这个问题,老答案,smart pointer
例如你前面提的scopedPointer,靠人工释放,要找出
哪里忘了释放resource是一件苦差事,请快点搞懂他吧
此外,QString是采用了implicity sharing的
这代表只要有一个"兄弟"还存在,QString的资源就不会被释放
而且QHash也一样是implicit sharing的
implicit sharing
http://doc.qt.digia.com/stable/implicit-sharing.html --------------------编程问答--------------------
有关于这几个问题,
1.ReleaseResource这里,我确认都被正确调用了;
2.那个例子,就是QHash嵌套的例子,没有这些方法,只是简单的利用QHash,在我这里的试验确实是不释放内存,这个不牵涉我自定义的数据结构,我用的4.8.1的库,Qt Creator 2.4.1,UBuntu 12.04LTS版本,是不是我的环境配置有问题呢? --------------------编程问答-------------------- 测试代码如下:
if(1)
{
QHash<QString,QHash<QString,QHash<QString,QString> > > Options;
for(int i=0;i<10;i++)
{
QHash<QString,QHash<QString,QString> > Tmp2;
for(int m=0;m<1000;m++)
{
QHash<QString,QString> Tmp1;
Tmp1.insert(QString::number(m),QString::number(m));
Tmp2.insert(QString::number(m),Tmp1);
}
Options.insert(QString::number(i),Tmp2);
}
}
return App.exec();
请您看,这是刚开始执行的时候,内存大小以及i值;
这是执行到中间的时候,内存大小,i值为9
这是最后的时刻,内存依然在5.7M没有变化,也没有释放.... --------------------编程问答--------------------
我也不知道发生了什么事情...可能是QHash用pool管理resource
所以resource暂时没有被释放?
我用的版本是Qt4.8.4,win764bits, mingw4.6.2
到这里去问问题吧,说不定是Qt4.8.1的bug?
http://qt-project.org/forums/
确定是bug而且Qt4.8.4也有一样的问题后可以到这里报告
https://bugreports.qt-project.org/secure/IssueNavigator.jspa?pager/start=50 --------------------编程问答-------------------- 其实if(1)没必要,++iter效率比较高 --------------------编程问答--------------------
竟然是英文的Form,这个,英文水平有限啊,看看还可以,说就............ --------------------编程问答--------------------
如果使用内存池的方式来管理的话,很长时间内,内存都不释放的.....
所以,我一直在说,十分搞不懂Qt的内存管理机制,或者说是Linux的内存管理机制...... --------------------编程问答-------------------- 忘了提醒你,我的环境一切正常 --------------------编程问答--------------------
在windows下,运行内存是释放的吗?
这么说,难道是Linux的环境有关,或者说是Linux下的内存管理存在问题吗? --------------------编程问答--------------------
说实话,我也不知道,爱莫能助
如果你确定真的有问题,我可以帮你到该论坛发问
能改进Qt的品质对大家都有好处
照你的测试方法,就算在win7下memory也不会跟分配memory前完全一样
可能有些resource被放到pool里头?
不过你若是频繁的释放和分配,memory的大小变化会维持在一定的范围内
在release版下,你仔细观察一下memory的变化好了
#include <QtCore>
#include <QtGui>
void memory_alloc_release()
{
QHash<QString,QHash<QString,QHash<QString,QString> > > Options;
for(int i=0;i<10;i++)
{
QHash<QString,QHash<QString,QString> > Tmp2;
for(int m=0;m<1000;m++)
{
QHash<QString,QString> Tmp1;
Tmp1.insert(QString::number(m),QString::number(m));
Tmp2.insert(QString::number(m),Tmp1);
}
Options.insert(QString::number(i),Tmp2);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
while(1){
memory_alloc_release();
}
QLabel w;
w.show();
return a.exec();
}
我的环境下,memory一直在5M~7.XM下变化
memory确实有不断的回收和释放
smart pointer的使用不难
快点掌握他吧,处理上层逻辑的时候
smart pointer会帮你省下很多时间的
至少你以后除错的时候不用再担心有哪里
忘了release resource
我以前用C的时候总是得将忘了release这个
可能性纳入计算,用了smart pointer后我再也不曾
为了这问题而烦恼了 --------------------编程问答--------------------
1.这个我没有Windows环境下的QT,一直在Ubuntu下测试
2.昨天晚上一直再查Linux的内存分配以及环境配置问题,看了这篇文章,linux 内存释放,http://blog.zol.com.cn/2322/article_2321774.html
3.我在Linux下试试看您的测试代码 --------------------编程问答--------------------
按照您的测试方法,用While的方式,内存确实在不断变化,从4.X~5.X之间变化,为什么单次执行不起作用呢~,非要用While的方式才能观察到内存的释放呢 --------------------编程问答--------------------
QDomDocument Doc;
QString Emsg;
int ELine,EColumn;
if(!Doc.setContent(&file,&Emsg,&ELine,&EColumn))
{
file.close();
Result=false;
}
现在的问题是这个了,这个QDomDocument在SetContent之后,内存会被占用,然后很难释放... --------------------编程问答--------------------
用同样的方法(34楼)测试看看?我估计是用了pool来控管memory才会造成这种现象 --------------------编程问答-------------------- 弱弱的问一下。如果有一个。QHash<QWidget*> m_hash;
这个你是怎么释放的? --------------------编程问答--------------------
这是一个存放QWidget指针的hash结构,在析构hash之前,先把指针指向的Widget释放,再析构hash
补充:移动开发 , Qt