当前位置:编程学习 > wap >>

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 --------------------编程问答--------------------
引用 1 楼 dext 的回复:
每一个元素 都要 delete。不能简单的clear

能delete的都delete了,请版主大大仔细看看呀,帮忙分析下 --------------------编程问答-------------------- delete this->StList;这句为什么不起作用呢 --------------------编程问答--------------------
引用 3 楼 ydpro 的回复:
delete this->StList;这句为什么不起作用呢

唉,明白了,刚做了个实验,QT的运行机制有问题,或者是不合理......感觉必须要在某个地方结束某种消息循环后,才会真正释放,不然内存占用一直被占用 --------------------编程问答--------------------
引用 4 楼 ydpro 的回复:
引用 3 楼 ydpro 的回复:
delete this->StList;这句为什么不起作用呢
唉,明白了,刚做了个实验,QT的运行机制有问题,或者是不合理......感觉必须要在某个地方结束某种消息循环后,才会真正释放,不然内存占用一直被占用

分配到栈上也不释放吗? --------------------编程问答-------------------- 不行啊 --------------------编程问答--------------------
引用 楼主 ydpro 的回复:
因为工程需要,对QHash进行封装,封装之后,进行Delete,但是内存并不释放,单独对QHash进行测试,发现没有问题,贴出代码,请教各位大神,看看那是哪里的问题~~~~~~
头文件如下:
#ifndef SETTABLE_H
#define SETTABLE_H
#include<QHash>
#include "settings.h"
#include<……


我怎么你觉得简单问题复杂化? 你为什么要new并持有一个QHash的指针,直接用栈对象不行?你看你为了它多写了多少代码。我看了下QHash的实现,它只有一个数据成员:包含指针的一个union,也就是说它只占用4 bytes,你确定你有必要在堆上创建?

另外,我不知道你的Setting指向的对象是谁负责创建?谁负责释放,如果你在外部new出它们,然后存在你的SetTable里面,而你没有负责delete,那就是内存泄露。
还有如果你不是在内存很吃紧的嵌入式环境开发,多用QSharedPointer等一类的智能指针吧,能让你的代码更加简洁。 --------------------编程问答--------------------
引用 7 楼 freebendy 的回复:
引用 楼主 ydpro 的回复:因为工程需要,对QHash进行封装,封装之后,进行Delete,但是内存并不释放,单独对QHash进行测试,发现没有问题,贴出代码,请教各位大神,看看那是哪里的问题~~~~~~
头文件如下:
#ifndef SETTABLE_H
#define SETTABLE_H
#include<QHash>
#include "settin……

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一个覆盖构造时候的空间(但块内存没看到你那边释放啊),你确认这样不会内存泄露?? --------------------编程问答--------------------
引用 9 楼 tt2com 的回复:
C/C++ code?1234SetTable::SetTable(){    this->StList=new QHash<QString,Settings*>();}
C/C++ code?12345SetTable::SetTable(const SetTable& s){    this->StList=new QHash<QString,Setting……


这是没问题的,这两个都是构造函数。 --------------------编程问答--------------------
引用 10 楼 freebendy 的回复:
引用 9 楼 tt2com 的回复:C/C++ code?1234SetTable::SetTable(){    this->StList=new QHash<QString,Settings*>();}
C/C++ code?12345SetTable::SetTable(const SetTable&amp; s){    this->StList=new……

是的,这都是构造函数,应该没问题的吧 --------------------编程问答-------------------- 这种内存的问题,没有完整的代码,很难得出什么结论。 --------------------编程问答--------------------
引用 12 楼 freebendy 的回复:
这种内存的问题,没有完整的代码,很难得出什么结论。

要不要我把相关的代码发给您,您帮忙给看看? --------------------编程问答--------------------
引用 13 楼 ydpro 的回复:
引用 12 楼 freebendy 的回复:这种内存的问题,没有完整的代码,很难得出什么结论。
要不要我把相关的代码发给您,您帮忙给看看?


例子我已经做好了,很简单的几个类~~~ --------------------编程问答--------------------
引用 14 楼 ydpro 的回复:
引用 13 楼 ydpro 的回复:引用 12 楼 freebendy 的回复:这种内存的问题,没有完整的代码,很难得出什么结论。
要不要我把相关的代码发给您,您帮忙给看看?

例子我已经做好了,很简单的几个类~~~

可以发我qq邮箱 --------------------编程问答--------------------
引用 15 楼 freebendy 的回复:
引用 14 楼 ydpro 的回复:引用 13 楼 ydpro 的回复:引用 12 楼 freebendy 的回复:这种内存的问题,没有完整的代码,很难得出什么结论。
要不要我把相关的代码发给您,您帮忙给看看?

例子我已经做好了,很简单的几个类~~~
可以发我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的问题 --------------------编程问答--------------------
引用 20 楼 stereoMatching 的回复:
>QHash<QString,Settings*>*StList;// modify by pointer

QHash指向的Settings*都要配合一个delete
你还没delete就呼叫clear
Settings的pointers所指向的resource在还没
delete前就都被你clear掉了
你这样子memory怎么可能会自动释放?

大幅……

是这样的,在一开始的代码中没有将代码贴完全,在类里有一个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来进行手工释放; --------------------编程问答--------------------
引用 21 楼 stereoMatching 的回复:
至于Qt的memory release机制,是基于parent and children的手法

1 : 你的father,children都是QObject
2 :  你的children必须成为father的children

这样一来,father在死亡的时候,就会把地下的children都杀光

你可以把他想像成资料结构的tree
最上层的node……

您说的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()么?求解惑!~~~ --------------------编程问答--------------------
引用 19 楼 dext 的回复:
如果实在搞不明白,就 坚持使用 new delete 配对的原则。
继承自 QObject 的类 会在 delete 的时候 通知 相应的容器类。所以不明白的话,就完全手动new delete。
你的例子中,每个Hash 中的 Settings* 没有被释放过吧。

恩,版主大大,这个确实没有被显式的在析构函数中释放过,因为在8楼还有代码贴的是手工释放的... --------------------编程问答--------------------
引用 23 楼 ydpro 的回复:
引用 21 楼 stereoMatching 的回复:至于Qt的memory release机制,是基于parent and children的手法

1 : 你的father,children都是QObject
2 :  你的children必须成为father的children

这样一来,father在死亡的时候,就会把地下的children都杀光

……


引用
难道要显式的去调用~QHash()么

不用,你的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 --------------------编程问答--------------------
引用 25 楼 stereoMatching 的回复:
引用 23 楼 ydpro 的回复:引用 21 楼 stereoMatching 的回复:至于Qt的memory release机制,是基于parent and children的手法

1 : 你的father,children都是QObject
2 :  你的children必须成为father的children

这样一来,father在死亡的时候,就会把……

有关于这几个问题,
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效率比较高 --------------------编程问答--------------------
引用 28 楼 stereoMatching 的回复:
我也不知道发生了什么事情...可能是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:……


竟然是英文的Form,这个,英文水平有限啊,看看还可以,说就............ --------------------编程问答--------------------
引用 28 楼 stereoMatching 的回复:
我也不知道发生了什么事情...可能是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:……

如果使用内存池的方式来管理的话,很长时间内,内存都不释放的.....
所以,我一直在说,十分搞不懂Qt的内存管理机制,或者说是Linux的内存管理机制...... --------------------编程问答-------------------- 忘了提醒你,我的环境一切正常 --------------------编程问答--------------------
引用 32 楼 stereoMatching 的回复:
忘了提醒你,我的环境一切正常

在windows下,运行内存是释放的吗?
这么说,难道是Linux的环境有关,或者说是Linux下的内存管理存在问题吗? --------------------编程问答--------------------
引用 33 楼 ydpro 的回复:
引用 32 楼 stereoMatching 的回复:忘了提醒你,我的环境一切正常
在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后我再也不曾
为了这问题而烦恼了 --------------------编程问答--------------------
引用 34 楼 stereoMatching 的回复:
引用 33 楼 ydpro 的回复:引用 32 楼 stereoMatching 的回复:忘了提醒你,我的环境一切正常
在windows下,运行内存是释放的吗?
这么说,难道是Linux的环境有关,或者说是Linux下的内存管理存在问题吗?
说实话,我也不知道,爱莫能助
如果你确定真的有问题,我可以帮你到该论坛发问
能改进Qt的品质对大家都有好处

照你的测……

1.这个我没有Windows环境下的QT,一直在Ubuntu下测试
2.昨天晚上一直再查Linux的内存分配以及环境配置问题,看了这篇文章,linux 内存释放,http://blog.zol.com.cn/2322/article_2321774.html
3.我在Linux下试试看您的测试代码 --------------------编程问答--------------------
引用 35 楼 ydpro 的回复:
引用 34 楼 stereoMatching 的回复:引用 33 楼 ydpro 的回复:引用 32 楼 stereoMatching 的回复:忘了提醒你,我的环境一切正常
在windows下,运行内存是释放的吗?
这么说,难道是Linux的环境有关,或者说是Linux下的内存管理存在问题吗?
说实话,我也不知道,爱莫能助
如果你确定真的有问题,我可以帮你到该论坛……

按照您的测试方法,用While的方式,内存确实在不断变化,从4.X~5.X之间变化,为什么单次执行不起作用呢~,非要用While的方式才能观察到内存的释放呢 --------------------编程问答--------------------
引用 36 楼 ydpro 的回复:
引用 35 楼 ydpro 的回复:引用 34 楼 stereoMatching 的回复:引用 33 楼 ydpro 的回复:引用 32 楼 stereoMatching 的回复:忘了提醒你,我的环境一切正常
在windows下,运行内存是释放的吗?
这么说,难道是Linux的环境有关,或者说是Linux下的内存管理存在问题吗?
说实话,我也不知道,爱莫能助
如果……

QDomDocument Doc;
        QString Emsg;
        int ELine,EColumn;
        if(!Doc.setContent(&file,&Emsg,&ELine,&EColumn))
        {
            file.close();
            Result=false;
        }
现在的问题是这个了,这个QDomDocument在SetContent之后,内存会被占用,然后很难释放... --------------------编程问答--------------------
引用 37 楼 ydpro 的回复:
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;
这个你是怎么释放的? --------------------编程问答--------------------
引用 39 楼 allencui0313 的回复:
弱弱的问一下。如果有一个。QHash<QWidget*> m_hash;
这个你是怎么释放的?

这是一个存放QWidget指针的hash结构,在析构hash之前,先把指针指向的Widget释放,再析构hash
补充:移动开发 ,  Qt
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,