在Window系统中new 和 delete的工作原理[1]

先举一个例子:

void memory_func1()

{

      int *p = new int (5);

      delete p;

      *p = 1;

 

      //lots of code ...

      char *pc = new char (3); //aha, crash

}

 

当运行到 char *pc = new char (3); 代码会 crash 掉,因为前面给已经释放的内存赋值。当这种情况发生时 ( 给已经释放的内存赋值 ) ,为什么会在下一次 new 时程序 crash 呢?

 

New 的工作原理: (VC, Debug)

实验代码:

void memory_func2()

{

      int *p = new int ;

      int *p2 = new int ;

      int *p3 = new int ;

      delete p;

      delete p2;

      delete p3;

      *p = 1;

 

      //lots of code ...

      char *pc = new char ; //aha, crash

}

 

在前三次内存分配中,内存的内容的对比如下:


原始 ( ) 第一次 new( )

 

第一次 new ( ) 第二次 new( )

 

 

第二次 new ( ) 第三次 new( )

 

可以看到,每一次 new int,内存的改动量挺大的。那么 new底层都作了什么?

F11跟进代码!

1

int *p = new int ;

 

2

void *__CRTDECL operator new (size_t size) _THROW1(_STD bad_alloc)

        {       // try to allocate size bytes

        void *p;

        while ((p = malloc(size)) == 0)

……

 

3:

extern "C" _CRTIMP void * __cdecl malloc (

        size_t nSize

        )

{

        void *res = _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);

 

…… 一堆函数调用,直到这里

4:

//一堆内存块检查

blockSize = sizeof (_CrtMemBlockHeader) + nSize + nNoMansLandSize;

/* 说明:

这里 blockSize = 40,

CrtMemBlockHeader 的结构如下:

pBlockHeadPrev

指针 , 指向前一个分配内存块

pBlockHeadNext

指针, 下一个

szFileName

指针,指向文件,估计用于内存影射文件,如果使用 new 等从内容分配则为 NULL

nLine

 

nDataSize

 

nBlockUse

 

lRequest

 

Gap[4]

填充 {0xfd,…}

他的大小应该是 32

nSize = 4 是要开辟的空间大小 , 在这里 ==sizeof(int)

nNoMansLandSize 未查到值,但根据上下文,应该是 4

*/

 

// 开始获取内存头块,并设置内容

pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize);

……

++_lRequestCurr;

 

_lTotalAlloc += nSize;

_lCurAlloc += nSize;

 

if (_lCurAlloc > _lMaxAlloc)

_lMaxAlloc = _lCurAlloc;

 

if (_pFirstBlock)

_pFirstBlock->pBlockHeaderPrev = pHead;

Else

_pLastBlock = pHead;

 

pHead->pBlockHeaderNext = _pFirstBlock;

pHead->pBlockHeaderPrev = NULL;

pHead->szFileName = (char *)szFileName;

pHead->nLine = nLine;

pHead->nDataSize = nSize;

pHead->nBlockUse = nBlockUse;

pHead->lRequest = lRequest;

 

/* link blocks together */

_pFirstBlock = pHead;

 

/*

经过上面调用后, pHead(0x003a9630) 的内容:

pBlockHeadPrev

0x003a91a8

pBlockHeadNext

0x00000000

szFileName

0x00000000

nLine

0

nDataSize

4

nBlockUse

1

lRequest

88

Gap[4]

……

 

*/

 

// 这里是为 Debug 所作的在内存边界填充 bNoMansLandFill(0xfd) ,我认为是为了调试内存越界的吧

memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize);

memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize);

 

// 然后把开辟的内存填充 bCleanLandFill (0xcd)

/* fill data with silly value (but non-zero) */

memset((void *)pbData(pHead), _bCleanLandFill, nSize);

 

上面就是分配的全过程,完成后内存内容如下:


(注:图中 prev next标反了! )

 

如果对上面过程进行总结,就是

如果要开辟的空间大小为 sizeof(int) = 4,

那么实际系统会申请大小为 32 + 4 + 4的空间,

其中前 32的大小为内存块头,存储内存分配信息,其中最后 4字节用 0xfd填充

中间 4字节为给用户的内存空间,在 debug下会用 0xcd填充

最后 4字节用 0xfd填充

 

这里面还有个关键的

pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize);

这里面又有什么过程?

跟进去后发现是这样:

#ifdef _WIN64

    return HeapAlloc(_crtheap, 0, size ? size : 1);

#else   /* _WIN64 */

    if (__active_heap == __SYSTEM_HEAP) {

        return HeapAlloc(_crtheap, 0, size ? size : 1);

……

调用了系统得 HeapAlloc 函数。

 

以上是在 Windows new debug 实现过程。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值