想确切的知道C++的delete到底是如何工作的 希望牛人指点一二

ziplj 2010-12-24 12:15:11
今天上班比较闲 想研究一下一直以来比较困惑的问题 就是 new的时候传入了一个大小的参数
但是delete的时候 却不需要参数
上网找了一下 类似于这种
http://blog.csdn.net/sanglipeng/archive/2006/10/24/1348500.aspx
里面所说

当我们使用 operator new 为一个自定义类型对象分配内存时,实际上我们得到的内存要比实际对象的内存大一些,
这些内存除了要存储对象数据外,还需要记录这片内存的大小,此方法称为 cookie。这一点上的实现依据不同的编
译器不同。(例如 MFC 选择在所分配内存的头部存储对象实际数据,而后面的部分存储边界标志和内存大小信息。
g++ 则采用在所分配内存的头 4 个自己存储相关信息,而后面的内存存储对象实际数据。)
当我们使用 delete operator 进行内存释放操作时,delete operator 就可以根据这些信息正确的释放指针所指向
的内存块。

我自己在VS2008中写了一个Test程序

struct Test1
{
char* pTest;
int iX;
int iY;
};

struct Test2
{
char szTest[128];
char szTest2[2];
};
void CMFCTestDlg::OnBnClickedOk()
{
Test1* pTest = new Test1;
Test2* pTest2 = new Test2;
delete pTest;
delete pTest2;
}

以第一个pTest为例 发现内存中的值是
cd cd cd cd cd cd cd cd cd cd cd cd fd fd fd fd ab ab ab ab ab ab ab ab ee
fe ee fe ee fe ee fe 00 00 00 00 00 00 00 00 10 00 0a 00 74 07 18 00 00 00
是在看不见 也不看不懂VC是如何给new的内存后面增加Cookie信息的
原本以为是Debug的问题 我在Release下面也测试了一下
Dump出来的内存是
0d f0 ad ba 0d f0 ad ba 0d f0 ad ba ab ab ab ab ab ab ab ab ee fe ee fe 00
00 00 00 00 00 00 00 db 03 05 00 ee 14 ee 00 78 01 39 00 78 01 39 00 ee fe
也没有发现想要的信息


跪求牛人解释一下 如何查看这种信息
...全文
659 39 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
yutaooo 2010-12-25
  • 打赏
  • 举报
回复
[Quote=引用 35 楼 libinfei8848 的回复:]
就是申请的实际内存比需要的内存大一点
是以为内存分配以页大小为单位,申请内存大小是页的向上整数倍
[/Quote]

你这个是不正确的。

ec++中说,new会有一些薄记工作。
LZ写了“此方法称为 cookie”
有些资料会说,元数据。

这些都是一回事。应用通过new或malloc()向分配器请求内存,分配器交给用户的内存块,叫做有效负载。有效负载是分配器分配出来内存块中的一部分。分配器实际上要分配稍大一些的内存块。比有效负载大多少呢?各个实现可以不同。比如,M$的可以和glibc的不同。大出来的那些内存块被分配器自己使用,应用程序是不使用的,虽然有些黑客程序的确访问这些本应只由分配器用的信息来实现特殊功能。里面一般存放的是,当前块是否使用的标志,当前这个块的大小等信息。delete之所以可以不用带一个尺寸信息的参数,那是因为,“当前这个块的大小信息”已经指出了需要释放多大的内存块,到空闲链中。而这个信息就是在new的时候,被薄记进入元数据的。

应用程序一般使用小额的内存块,这于内核中的内存分配器不同。内核中的确有以页为单位分配内存的分配器。但,这不适用于应用层,不然要有多少内存被闲置呀。
ziplj 2010-12-25
  • 打赏
  • 举报
回复
[Quote=引用 35 楼 libinfei8848 的回复:]

就是申请的实际内存比需要的内存大一点
是以为内存分配以页大小为单位,申请内存大小是页的向上整数倍
[/Quote]自己参看13L
ziplj 2010-12-25
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 yutaooo 的回复:]
给楼主建议,不要在c++的delete上追寻答案。要从malloc() free()中探索。这是因为,delete定义的是语意,找不到实现。而malloc() free()可以找到实现,能明明白白的告诉你某个实例如何产生效果。当了解清楚了某个分配器的实现,那么,其它的分配器在概念上是一样的。

我对分配器的了解,是从CSAPP中开始的。建议LZ也看看CSAPP的相关章节。

之后,看一下早……
[/Quote]Thanks Debug下一直单步跟踪就可以跟踪到Debug下的Cookie的数据结构
Meteor_Code 2010-12-24
  • 打赏
  • 举报
回复
new开出来的空间尺寸信息和地址信息是系统在内存管理目录中保存的,大家不用操心,至于new出来的信息到底是什么,我知道一点
Release下,是完全随机的东西,没有意义,道理很简单:上次使用这快内存时留下的,也可能是系统的某些动作留下的
debug下,申请出来的空间全部被初始化为cd,其实应该说把能够分配的空间都初始化为cd了,你申请的只不过他没有清理而已
cd其实是机器码:int 3;就是调试中断,这是唯一一个可以在保护模式下任意使用的中断.vc的调试器负责完成这个中断.他把debug的数据始化为cd,就是在你的程序崩溃,发生错误的转移时可能转移到这些内存上,然后马上int3,就进入了他的调试器.
而Release下根本没有调试器始化为cd没意义.
所以在调试情况下检查空指针还应该判断0xcdcdcdcd,这样的数据.
这是我知道的一点,不知到对LZ是否有用
龙哥依旧 2010-12-24
  • 打赏
  • 举报
回复
用zhao1zhong4的话,看看汇编就知道了,调试环境atl+8!
不过我觉得你的确是闲的,C++程序员研究它干啥?
:)
feng4206yu 2010-12-24
  • 打赏
  • 举报
回复
如果不知道cookie信息结构,当然什么都看不出来.
job82824 2010-12-24
  • 打赏
  • 举报
回复
我觉得可以这样理解。new操作就是把堆中的一些空间标记下,告诉编译器这些空间已经在用了,下此再new的时候就不会重叠在一起了;delete就是把这些空间的标记去掉了,让它们回到未分配的堆中,告诉编译器这些空间又可以再用了。动态分配内存空间时要考虑字节对齐的问题,否则就可能内存泄露了。
libinfei8848 2010-12-24
  • 打赏
  • 举报
回复
就是申请的实际内存比需要的内存大一点
是以为内存分配以页大小为单位,申请内存大小是页的向上整数倍
赵4老师 2010-12-24
  • 打赏
  • 举报
回复
heapwalk
pwalk
pwalker
赵4老师 2010-12-24
  • 打赏
  • 举报
回复
《Windows核心编程》
《深入解析Windows操作系统-Windows Internals》
yutaooo 2010-12-24
  • 打赏
  • 举报
回复

给楼主建议,不要在c++的delete上追寻答案。要从malloc() free()中探索。这是因为,delete定义的是语意,找不到实现。而malloc() free()可以找到实现,能明明白白的告诉你某个实例如何产生效果。当了解清楚了某个分配器的实现,那么,其它的分配器在概念上是一样的。

我对分配器的了解,是从CSAPP中开始的。建议LZ也看看CSAPP的相关章节。

之后,看一下早期分配器的设计原理。一篇非常著名的文档描述了这些原理。我的第二步是看的这个,因为它概念比较简洁,没有牵扯到目前的多线程环境下的lock-free编程之类繁琐的内容。链接是:http://g.oswego.edu/dl/html/malloc.html

再后面,看一些黑客方面资料吧。熟悉一些应用。比如堆溢出什么的。

再再后面,也许是最新版本glibc中分配器的实现。我是没敢看,这个一定是非常繁琐的,我计划是把并发算法学习到一定程度再仔细去看的。

new delete是c++的内存分配期,本质上就是分配算法的具现,这些算法有专门的书籍描述,什么首次适配,最优适配等等。再加上,现在又把并发编程提到了一定高度,并行算法也加入了分配器实现。总的来说,学好分配算法+并发算法就是实质。

另外,关于0xcdcd这些东西。真要深究,也许会走到系统层哦。
lzfbird 2010-12-24
  • 打赏
  • 举报
回复
研究一下还是可以的。不过不开发操作系统的话,一般用不着考虑这么多。

taodm 2010-12-24
  • 打赏
  • 举报
回复
不要试图深究这东西,其它值得多花时间学的东西多着呢。
hw_henry2008 2010-12-24
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 ziplj 的回复:]

Debug模式下 VC 申请内存 本质上还是调用HeapAlloc来完成内存的申请
因此 由于Windows源码问题 研究下去基本无解 而且如果OS来做这种事情 上面的疑惑感觉就不是太难理解了 以我个人感觉而言 delete的工作流程应该不是Blog里面说的那样 而是全部由OS来管理了 new出来的大小根本就不在new的内存的前面 或者后面

以下所说均在Debug模式下
虽说结果不是……
[/Quote]

正解,再微软面试题里见过
gules 2010-12-24
  • 打赏
  • 举报
回复
这个所谓的cookie确实是平台及运行时库实现相关,研究它没有什么普遍(通用)实际意义,知道有这个机制就行了;最多也只能说是针对某一特定平台学习内存管理机制罢了。
  • 打赏
  • 举报
回复
去看看windows核心编程 有一章专门讲这个的,很不错
无言猪 2010-12-24
  • 打赏
  • 举报
回复
要看你的CRT堆分配模式,通常是系统模式。也就是new实际是直接jmp到RtlAllocateHeap,delete直接到RtlFreeHeap.然后在Release模式下,你得到的地址-8就是这块内存的head地址,也就是_HEAP_ENTRY,前2个字节就是你这块内存地址的大小,要乘以粒度系数,一般是8.
  • 打赏
  • 举报
回复
好吧,我没有深入了解过。。
  • 打赏
  • 举报
回复
new出的内存要大于申请的内存!多出来的用于存放这块内存标识,比如大小等!

这样在delete的时候就不用给大小,而直接在new出来的那块内存开头去查看,便可知道需要释放掉多少内存!
Defonds 2010-12-24
  • 打赏
  • 举报
回复
内存分析
加载更多回复(13)

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧