C++中执行了delete m; 后会怎么删除m群好友本身吗?

C/C++语言学习
共有1066位成员   人气指数 -   最新排名 -
【话题】好像指针C++中的指针没有那么容易被delete掉~~~高手请进
10:01:49 来自:李梦琪 浏览数:316次
两个关于delete内存的问题,发现分配的内存都干不掉
1.代码运行完step 1以后,手持设备上的可用内存从27MB,骤降为1MB,step2以后,内存基本上没有任何变化。 请问如何能够正确释放内存
C/C++ code
CString *m_pStr=NULL;
std::deque&CString *&
for(int i=0;i&1000000;i++)
m_pStr=new CS
list.push_back(m_pStr);
for(int i=0;i&list.size();i++)
//使用这种方式无法释放掉内存
m_pStr=list[i];
if(NULL!=m_pStr)
delete m_pS
m_pStr=NULL;
list.clear();
2.我在Mobile上的内存管理器观察了一下内存的变化,发现采用这种常用方式分配的内存,居然也不能正确释放,请问这是怎么回事?
C/C++ code
CString *m_pStr[100000];
for(int i=0;i&100000;i++)
m_pStr[i]=new CS
for(int i=0;i&100000;i++)
delete m_pStr[i];
但是使用如下的方式是可以在内存管理器中正确释放的
C/C++ code
CString *m_pStr=new CString[100000];
delete [] m_pS
yu714173回复于12日21点40分 
恩,我在实际工作中借鉴了Symbian的瘦模板技术,模板中没有对象的概念,只有指针的概念,但是这跟这个贴的主题没有关系,因为任何一种技术,无论封装的多么好实现的多么精彩,它们的根都是new和delete,如果它们不能正常工作,那么谈任何别的技术都是没有意义的。
小雅雅回复于13日16点21分 
我记得好像看过
你一个指针一个指针的申请空间
断断续续的 编译器没那么智能 没看出连续释放的地址有什么联系
不回因为你释放一个小空间 就内存回收 主要是性能考虑
就像一个程序 你 这申请个INT 那申请个CHAR 它不能你释放一次
他就把内存指针 还有已分配内存数量之类的东西修改一次
而 你用数组了
编译器就知道这些是一起的& 而且数量很大 值得从新更新下内存使用信息
大概这样吧 我也是有那么点印象 说的不对请改正
问下 是Symbian吗
zhn666回复于14日12点38分 
顶起 继续学习 等待高手来答疑
郭培进回复于15日09点39分 
那位朋友想要,50W次的new和delete的过程中,物理内存和虚拟内存的变化情况,可以留下邮箱。我发给大家。
另外,刚才忘记提,虚拟内存在new的过程中也是线性下降的,delete的过程中保持一个常数不变。
百合守护者回复于16日08点24分 
以下测试实验环境:VS2005,WM5.0,硬件设备是AMOI的N810。
由于我的框架是WTL,为了避免是CString本身的问题,我将new的对象改为了wchar_t
程序修改为:
char ps[256]={0};
const int N=1000000;
wchar_t **ppStr=new wchar_t*[N];
int nCount=0;
for(int i=0;i &N;i++)
ppStr[i]=new wchar_t;
if(NULL==ppStr[i])
MessageBox(L&内存空间已满&);
for(int i=0;i &N;i++)
delete ppStr[i];
ppStr[i]=NULL;
再程序的运行过程中记录了内存的变化(通过GlobalMemoryStatus),50W条级别时,运行前和运行后的变化如下。
dwMemoryLoad:53
总物理内存:
可用物理内存:
总虚拟内存:
可用虚拟内存:
总页文件数:0
可用页文件数:0
dwMemoryLoad:53
总物理内存:
可用物理内存:
总虚拟内存:
可用虚拟内存:
总页文件数:0
可用页文件数:0
我在程序中每new或delete一个对象时就用GlobalMemoryStatus取一次内存快照并记录到文件中,发现经过251次new操作以后物理内存一直都是,然后104次都是 ,再往后的52次都是,然后是251次的,之后是167次的 ,50万次执行完毕后,最后的127次为,可以看出内存并不是每次new都会马上分配,667264之间差了4096个b,差不多就是251个wchar_t的大小,但是663168之间差了16384b,2048个字节,显然不是52个wchar_t的空间,但是后面38592 也是4096个b,差不多也是251个wchar_t,另外我计算一下两次分配时内存下降的数量,绝大多数情况是4096,我猜测这是不是由于,分配出的内存没有被使用,所以内存管理器为了保证效率,在一段时间后统一分配一块儿内存区域。我觉得4096这个数字应该就是WM系统中分配内存的最小单位了,中间那些差值不为4096的情况,可能跟我调用了系统API以及写文件有关。
delete也是,并不是每次delete后内存都会变化,内存也是一段时间变化一次,绝大多数的时候,相隔两次获取内存的时候,内存容量之间的差值为8192,因此可以认为,8192是回收内存的最小单位。与new的线性减少不同,delete时,可利用内存从开始的到最后的,中间的过程是非线性的,可利用内存始终没有超过15M过。
最后总结一下,delete和new都不是马上会从堆中得到内存空间,而是由操作系统根据内存的使用情况统一分配和回收的,new对象的过程中,可利用内存线性下降,delete对象的时候,可利用内存非线性波动,但是波动范围始终不会超过1MB。
delete后延迟一段时间变化内存是可以理解的,用前面各位朋友的解释可以解释通。new内存的时候,为了保证效率,没有用到的内存块暂不分配,也是合理的策略。delete的内存没有回收,还是无法解释。
另外,我试验了一下,调用一个循环分配1000000个对象并在另一个循环中delete掉以后,再次进行相同的过程,new的时候会发生内存不足的异常。因此,使用的时候才回收,这个概念也是不对的。
sophieii回复于16日23点30分 
lw4691363回复于17日05点00分 
马敬融回复于17日07点18分 
To wuyu637
这样也解释不通,我将CString *m_pStr[100000]修改为CString **m_pStr=new CString*[100000],后面代码不变,还是有相同问题。
chensl回复于17日09点24分 
学习了& 继续等待在WM有过相关经验的牛人来释疑
炫彩少年回复于17日11点16分 
首先是这个,我没看明白。LZ 的 step 1 是分配内存的过程,怎么会出现“内存骤降”。
然后是这个:
C/C++ code
CString *m_pStr=new CString[100000];
delete [] m_pS
比较这个内存分配/释放过程,于前述的分配释放过程。我找到的差别是,这里一次性分配了大块的连续内存块。而其他分配方式,总是多次分配小额内存块。
总的来说,App 向 malloc/new 这样的分配器请求内存,而 malloc/new 在堆不足以满足 App 请求时向内核请求内存。这是个 2 阶段不同层次的请求。当 App 把通过 free/delete 把内存归还时,只是放入的堆这个内存池,并不会引起内层级别,把内存归还给内核。
而根据 LZ 观察,的确有内存归还内核了。就发生在大块内存分配的时候,如上面的代码这种情况。而我怀疑,你 “new CString[100000]” 这样大小的内存块,根本不再预先考虑的范畴内,属于特殊情况(太大)。分配算法也由此进行了特殊的处理,根本不准备组织到空闲链当中。毕竟,LZ 的开发平台上,内存是比普通计算机更稀缺的资源。
对这种情况,是否考虑自己做分配管理,不用默认的 operator new。也希望 LZ 能找到将内存归还内核的系统调用,有点象VirtualFree这种的。
曹丹枫回复于17日12点54分 
czy88回复于17日14点31分 
CString *m_pStr=new CString[100000];
delete [] m_pS
既然这种方式可以很好的解决问题。何必用for循环,单个delete呢?
SUZHIKAI回复于17日15点54分 
chenqy回复于17日17点18分 
LZ 这段代码不就是 0楼 中的第二个例子吗? LZ 在0楼不是说,这段代码不能正确释放内存吗? 怎么到 38 楼又变成能够正确释放了? 我误解什么了吗 ?
jeanchen回复于17日18点30分 
wangyumeng716回复于17日19点36分 
紫光★瞬间№回复于17日20点36分 
路过受教了
xuexi130回复于17日21点31分 
先留着以后看吧
huagh回复于17日22点18分 
其实这是最合理的.
有很多时候一个容器存放的内容并不是同一个类型的,然而容器都是需要有确定的管理类型,所以一般都是把资源生成好然后管理指针的.
hyqhyq2008回复于17日23点06分 
我没有新的想法,不过我觉得楼上几位已经提供了有用的信息,这里小结一下。
问题的关键仍然在于 WM 的内存管理方式。根据楼主提供的用例,我觉得最可能的情况是:
1、内核分配给进程的仍然是大块的内存(虽然进程启动时并不分配,只在需要时分配);
2、仅当整块内存空闲时,才可能归还给内核;
3、即使整块内存空闲,也可能不立即归还。
一般来说,第1点是成立的。因为内核分配的效率问题,操作系统会这样做。WM 是否如此,可以测试一下:对于 1000000 个 new,楼主可以每执行一次 new 就看一下内存情况,是否每次都发生(匀速且缓慢的)增长。如果不是每次都增长,则第1点成立。
当第1点成立时,第2点肯定成立。问题在于第3点。楼主提供的用例三(大数组)似乎暗示第3点不成立;但是用例一、二(特别是用例二)支持了第3点。【注1】比较用例二和三,发现它们主要有以下两点不同:
1、用例二多次分配和释放小块内存,用例三一次性分配和释放大块内存;
2、用例二使用 new 和 delete,用例三使用 new[] 和 delete[]。【注2】
首先说一下第2点。WM 有可能对数组采用不同的方式:比如数组一旦释放就尽快归还内核,而非数组不是这样(虽然我觉得这种可能性比较小,但还是提一下)。用以下代码可以测试第2点是否有用:
C/C++ code
CString *m_pStr[100000];
for(int i=0;i&100000;i++)
m_pStr[i]=new CString[1]; // 修改为数组方式
for(int i=0;i&100000;i++)
delete[] m_pStr[i]; // 修改为数组方式
如果执行结果与用例二一样,那么证明和数组无关;否则的话,问题就出在数组上。
假设问题和第2点无关,现在再来看第1点。假如“即使整块内存空闲,也可能不立即归还。”成立,那么不归还的原因很可能与使用情况有关。对于用例三,系统很容易知道整块内存空闲了,因此立即归还;而对于用例二,delete后获得的是一长串空闲内存链表,系统可能无法立即知道整块内存空闲;也可能即使知道了也暂时不收回【注3】。系统可能在定时整理后回收,也可能只在需要时回收。对于后者,楼主可以考虑再运行一个程序,申请大量内存,看看系统是否会在内存不足时收回前一个进程的内存。
问题就分析到这里,没有什么新的东西,主要是对楼上诸位的小结。我们都没有用过 WM,因此很大程度上只是猜测,供参考。
要很好地了解前因后果,楼主可以考虑以下做法:
1、学习一下 WM 的内存管理方式——无论如何,自己猜测不如学习标准文档;
2、设计更多的测试用例,仔细分析各种可能的情况——这是最一般的方式,最后总能找到原因,但是成本不受控制;
3、使用 WIN API(包括 WM 特别提供的)考察进程运行时内存的具体情况——确切地了解内存状态,可以快速找到原因。
1、用例一使用 std::deque. 不幸的是,在使用 std::deque 的过程中,要不断的为指针申请新的内存,而 clear() 并不保证释放它们。因此,执行完所有的 delete 后,很可能仍然没有整块的空闲内存。因此用例一不具有代表性。
2、无疑17楼的说法答非所问。但是从中可以得到启发,因此有了第2点。
3、这涉及到对内存的“智能化”管理。如果进程之前大量地申请内存,那么系统研判此后仍然可能存在大量的申请,因此暂时保留。诸如此类对用户行为的学习有可能存在于系统中;当然,也可能不存在,呵呵。
C/C++语言学习的其他话题...
热门脚本语言:当我们申请一个动态数组& int *a = new int[m];
然后 对第m+1个元素赋值 a[m] = 1;
最后执行&&&&delete []a;
就会卡死在delete 语句这里,或者报错。
改成&delete[m]a; 或者 delete[m+1]a; 也都会有同样的问题。
究其原因是没有搞清楚new 和 delete 的原理。
原来&:( 引用自 &)
通常状况下,编译器在new的时候会返回用户申请的内存空间大小,但是实际上,编译器会分配更大的空间,目的就是在delete的时候能够准确的释放这段空间。
这段空间在用户取得的指针之前以及用户空间末尾之后存放。
实际上:blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandS其中,blockSize 是系统所分配的实际空间大小,_CrtMemBlockHeader是new的头部信息,其中包含用户申请的空间大小等其他一些信息。nNoMansLandSize是尾部的越界校验大小,一般是4个字节“FEFEFEFE”,如果用户越界写入这段空间,则校验的时候会assert。
用户new的时候分为两种情况
A.new的是基础数据类型或者是没有自定义析构函数的结构
B.new的是有自定义析构函数的结构体或类
这两者的区别是如果有用户自定义的析构函数,则delete的时候必须要调用析构函数
那么编译器delete的如何知道要调用多少个对象的析构函数呢,答案就是new的时候,如果是情况B,则编译器会在new头部之后,用户获得的指针之前多分配4个字节的空间用来记录new的时候的数组大小,这样delete的时候就可以取到个数并正确的调用。
哦~~&& 想问题 做事情, 还是要仔细。。。 不能想当然。。。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3969次
排名:千里之外C++中new和delete的用法
C++中new和delete的用法
C++成长之路
首先,new和delete运算符是用于动态分配和撤销内存的运算符。
一、new用法
  1.开辟单变量地址空间
  使用new运算符时必须已知数据类型,new运算符会向系统堆区申请足够的存储空间,如果申请成功,就返回该内存块的首地址,如果申请不成功,则返回零值。
  new运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有标识符名。
  一般使用格式:
**格式1:指针变量名=new 类型标识符;
格式2:指针变量名=new 类型标识符(初始值);
格式3:指针变量名=new 类型标识符 [内存单元个数];**
  说明:格式1和格式2都是申请分配某一数据类型所占字节数的内存空间;但是格式2在内存分配成功后,同时将一初值存放到该内存单元中;而格式3可同时分配若干个内存单元,相当于形成一个动态数组。例如:
  1) //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址。int *a = new int 即为将一个int类型的地址赋值给整型指针a
  2)int *a = new int(5) 作用同上,但是同时将整数空间赋值为5
  2.开辟数组空间
  对于数组进行动态分配的格式为:
  指针变量名=new 类型名[下标表达式];
delete [ ] 指向该数组的指针变量名;
  两式中的方括号是非常重要的,两者必须配对使用,如果delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的指针,会产生回收不彻底的问题(只回收了第一个元素所占空间),加了方括号后就转化为指向数组的指针,回收整个数组。
  delete []的方括号中不需要填数组元素数,系统自知。即使写了,编译器也忽略。
  请注意“下标表达式”不必是常量表达式,即它的值不必在编译时确定,可以在运行时确定。
  一维: int *a = new int[100]; //开辟一个大小为100的整型数组空间
  二维: int **a = new int[5][6]
  三维及其以上:依此类推.
 二、delete用法
  1. 删除单变量地址空间
  int *a =
   //释放单个int的空间
  2. 删除数组空间
  int *a = new int[5];
  delete []a; //释放int数组空间
  三、使用注意事项
  1. new 和delete都是内建的操作符,语言本身所固定了,无法重新定制,想要定制new和delete的行为,徒劳无功的行为。
  2. 动态分配失败,则返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。
  3. 指针删除与堆空间释放。删除一个指针p()实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身(指针p本身并没有撤销,它自己仍然存在,该指针所占内存空间并未释放),释放堆空间后,p成了空指针。
  4. 内存泄漏(memory leak)和重复释放。new与delete 是配对使用的, delete只能释放堆空间。如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。
  5. 动态分配的变量或对象的生命期。我们也称堆空间为自由空间(free store),但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放,往往会出错。
  6. 要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问。
用new和delete可以动态开辟和撤销地址空间。在编程序时,若用完一个变量(一般是暂时存储的数据),下次需要再用,但却又想省去重新初始化的功夫,可以在每次开始使用时开辟一个空间,在用完后撤销它。???
7.指针变量名=new 类型标识符(初始值),这个用法要注意初始化时不能超过分配的内存大小,如下错误的初始化方法:
char *zf = new char(“Hello”);
char *zp = new char[6];
zp = “Hello”;
8.多维数组:
int (*p2)[10] = new int[2][10];
int (*e)[2][3] = new int[34][2][3];
9.运算符new会自动调用类的构造函数。
10.malloc和free
1)malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
2)对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
3)因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
4)C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
5)new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。
而malloc和free从不调用构造和析构函数,他们只是简单的分配内存
我的热门文章
即使是一小步也想与你分享

我要回帖

更多关于 怎么删除m群好友 的文章

 

随机推荐