我需要载入一个文件的数据,并且将数据读到内存中,在这个读取的过程中,我不断的new空间(类型是自定义的一个类),并且把首地址赋值到一个CTypedPtrArray类型的数组。这个数组比较大,动辄上万个元素。
    关闭文件时,我希望释放内存,就是在另外一个函数中,把元素一个个取出来delete。
    现在的情况是,debug版,能够正常的释放空间,比如在任务管理器查看程序占用的内存,打开文件前占用100M,打开后是150M,关闭文件时这个占用的内存可以降到100M左右,但是release版本却不行,可能只降到120M。但是release也不会报错,关闭时正常运行。
    我检查过,delete的次数是一样的,并且检查了部分delete的空间大小(用sizeof(*p)查看)也是一样的。
    我查过两个编译的版本的区别,但是找到的说的都是两者编译的时候一些参数的设置的区别,还有就是类似变量初始化的问题,也有自定义消息响应函数的问题。我试过编译的一些参数的设置没办法解决,还有变量初始化这些都没问题。    请各位支支招!!!!分数可以继续加。谢谢各位高手了。

解决方案 »

  1.   

    5555~~~单纯这部分的代码比较简单,已经看了好多遍了
    就是在一个地方new,然后赋值
    在另外一个地方不断的GetAt[i],然后delete p;
      

  2.   

    你如果能确定没有内存泄露,用任务管理器查看程序占用的内存的可信程度应该低一些。
    是仅仅刚结束的时候多占20M 内存还是以后一直这样?
    频繁启动这个release的exe就能看出是不是吃内存,如果就保持这个水平我觉得你完全可以忽略不管它。
      

  3.   

    还是代码的问题,debug版和release的主要区别就在于对指针的初始化等方面,在这些方面检查一下。
      

  4.   

    release版本打开时内存是多大?
      

  5.   

    当然release打开时占用的内存跟debug不相同,我前面给的release的数据只是大概的比较一下。
    比如打开文件前,release占用100M,打开后150M,关闭文件后就是120M左右。
    现在关键不是这里占用多少,而是这个数据差跟我打开的文件大小有关(其实就是跟new的次数有关),如果我打开的是几百兆的文件的话,这个相差就有几百兆甚至1g了。
    至于指针,我是这样用的。假设存储数据的类是CData.它有自己的构造函数,分别对各个数据成员赋值。
    CData* p=new CData();
    p->member1=*******;//多条类似的语句赋值给部分成员,一部分成员没有赋值,赋值验证正确。
    ……
    m_Array.Add(p);//然后把这个p存到CTypedPtrArray类型的数组m_Array.
    释放的时候:for(int i=0;i<m_Array.GetSize();i++)
    {
       CData *p=m_Array.GetAt(i);
       delet p;
    }
    m_Array.RemoveAll();这样的操作有什么问题么? 
      

  6.   

    从CData,m_Array的释放来看,没什么问题,你要看CData中是否还有别的数据等没有释放...
      

  7.   

    既然new和delete次数一样,应该没有问题。你查看一下进程的虚拟内存变化是否正常,任务管理器默认显示的是物理内存,是由系统调度的,通常不用管它。
    对于频繁分配内存的情况,最好按照逆序释放,即后分配的内存先释放,这样程序的性能会好一些。
      

  8.   

    for(int i=0;i <m_Array.GetSize();i++) 

      CData *p=m_Array.GetAt(i); 
      delet p; 
    } 没有问题。
    这个东西我一般都倒删,你这里用GetAt是没事,要是删除就出事儿了。
      

  9.   

    来了一个五星,两个钻石啊
    lz幸运啊
    还是看看CData的内部吧
      

  10.   

    用 boundschecker 查下内存是否有泄漏
      

  11.   

    很标准的代码啊。有几个测试办法。
    第一,把CData类new和delete的代码注释掉,看看内存变化如何。
    第二,把CData类换成一个简单类,比如就一个整型成员变量的类,看内存变化如何。
    另外,不妨把你CData类的成员变量贴出来看看,另外确定该类的成员不会有泄漏问题。包括句柄等,都已释放。
      

  12.   

    释放的时候: for(int i=0;i <m_Array.GetSize();i++) 

      CData *p=m_Array.GetAt(i); 
      delet p; 

    m_Array.RemoveAll(); 试试在这后面加上freeextra,曾经有个项目,在VC6下面与楼主的释放代码一样,没什么问题,但在2005下报内存泄露,在这后面加上
    m_Array.FreeExtra();就没事了.可以试一下.
      

  13.   

    看了,虚拟内存跟物理内存效果一样,也是没降下来。另外已经学习各个倒过来删除内存了。只是问题还是没解决呜呜cdata又看了遍,不存在new之类的情况,并且调试Release时,观察到类的各个成员的值都能被清除
      

  14.   

    按我说的方法试试。逐步定位问题所在。
    CData的成员变量不方便给出么?
      

  15.   

    我提个建议,你不妨直接用GlobalAlloc来申请内存看看,不用new。new则是c++的标准函数,在windows的vc++编译器中,new在申请内存最终调用的是GlabalAllock,不过new还会调用类的构造函数。
      

  16.   

    以前遇到过这样的情况,但是很神奇的是换成了HeapAlloc之后,就不会出现如此大的内存消耗差异了
      

  17.   

    类中没有new等操作。另外我刚才用你说的第二个方法测试了一下,弄了一个类,里面包含三个 cstring,也是释放不了内存,但是在debug下可以释放。看来跟这个类无关
      

  18.   

    是啊,所以问题不在你怀疑的这个CData上,还是和你系统其它地方有关系。
      

  19.   

    m_Array.FreeExtra();
    试过啦??
      

  20.   

    这个问题很可能跟mfc的数组类的实现有关,如果楼主说的这个差值不随文件操作次数的增加而增大,那就不用
    管它了
      

  21.   

     试过了,freeextra不行
    另外,我自己用了一个指针数组来保存指针,还是一样的效果。
      

  22.   

    呃,我真想不出问题还能在这之外啊。想用malloc来分配内存试试,但是类里面有Cstring,分配的大小不知道怎么搞。直接用Sizeof到给Cstring赋值时会报错
      

  23.   

    这个没办法,内存是这样子的,比方你先new一片内存,、系统就会在原来内存最末页尾上加上24字节+你分配的字节,再分再在后面加,当你删除了前面一个内存里候,系统把那小部分还原成0xfe,如果该页面上还有一个零散的内存,那么就不会删除该页面,就是说内存大小不变,只有当一个页面里所有字节都末使用,系统才会把该页面删除,效果就是看到内存变小了,从这里可以看出,分配次数越少越好,还有就是后分配的如果先删除,就会符合系统分配的方法,就会很容易看到内存按你想法在变化,如果没按顺序,就会有一些页面因为仅有小部分数据而被系统保留着空间
    可以试试分配的链表头设为最末分配的内存,这样从头删除就符合系统顺序了,
    也可以一次性分配CData *p[N]数组,删除的时候直接用delete[]p;
    还有可以用C结构,如果有字串,使用类似typedef struct {
      other data;
      int len;
      char str[1];
    }EXP;分配时候EXP * p = (EXP*)new char[sizeof(otherdata) + sizeof(int) + len]//len为你要分配的字串长度,这样把内存分配在一个紧凑的位置,删除时候只需直接删除delete [] p;就把所有数据和字串一次删除了,性能要好些
      

  24.   

    有地方说错了,呵呵可以一次性分配CData *p[N]数组,删除的时候直接用
    for(int i = N-1;i>= 0 ;--i)
      delete p[i];
    忘记析构函数的特殊性了,
      

  25.   

    非常感谢pady_pady的详细负责讲解。我会照你说的方法试试。
    我现在的情况是需要在一个很大的文件中,文件有多少行逐行读取数据,一行数组占据一个Cdata,这样一次分配的话造成一个问题就是我必须知道文件有多少行,大的文件可以有60万行,所以循环一次就需要花了7.8s的时间。
    不过如果实在没更好的办法,而像你这样的方法又的确能够释放内存,也只能这样了。
      

  26.   

    因为查了一些release和debug的资料,很多说的是debug自己定义了new用来检测内存泄露。所以我想像前面biweilun所说的,使用其他函数来分配内存,但是现在的问题是,我的Cdata里面有很多的CString,如果用其他函数,比如malloc来分配的话,需要知道大小,比如malloc(sizeof(CData)),但是这样的话,一旦给CString对象赋值的时候,就会出错。其他分配内存的函数也都是这样的情况。
        但是因为成员变量很多,使用的地方更多,所以我也不方便把这个CString 改成其他的类型,大家有什么办法可以给CString分配内存么?
      

  27.   

    可以这样分配啊,CData *p = (CData*)new char[nCount * sizeof(CData)];
    //初始化#pragma push_maco("new")
    #undef new
    for(int i = 0;i<nCount;++i)

       ::new((void*)&p[i])CData;
    }
    #pragma pop_maco("new")//delete
    for(int i = nCount - 1;i >= 0;--i)
       p[i].~CData();
    delete [] (char*)p;
    //这样子,就能自动调用析构函数了和构造函数了,主要是要注意初始化的删除的顺序相反就很容易释放内存。
      

  28.   

    pady_pady后面说的有点复杂。我不太懂
    用了string代替了结构中所有的cstring,释放的内存会多一些
    结贴吧,另开一贴讨论这个问题