delete用来释放通过new创建的内存,想必你已经十分熟悉。你也知道如何使用了。或许你并不清楚,不管如何,都有必要看看内部的实现机制,可以加深理解,让你对使用规则有一个更好的认识,而不是模糊的记忆。
在delete的内部执行的过程大致如下:
最先检测的是传入的唯一的一个指针参数,如果指针为空,不管delete多少次都没有关系。因为在内部首先就是判断指针是否为空,如果为空,则直接返回。
因为new操作是在进程的堆中分配内存的,而一个进程有可能有很多的线程,而进程堆作为一个进程的多个线程的公共资源,访问时必然不能多个线程同时访问,否则会出现重复分配和释放的情况。用术语讲,进程堆就是临界资源。对临界资源的访问,每次只能允许一个访问。因此,一个线程在请求堆分配内存前,是要锁定堆,不允许其他进程操作。加入堆已经有一个线程在访问,则自己要等待。分配好内存后,就会解锁堆,让其他线程可以去分配内存。在锁定期间,线程就开始分配内存。
同样,delete去释放堆内存,也是要锁定后才操作,操作完后解锁的。原理同new一样。
delete在释放内存时,首先是去获得指向堆的内存起始地址的指针,然后去修改内存块的类型,将使用状态修改为未使用状态,则达到释放的效果。下次再分配堆内存时,检测到这些内存块的状态是未分配状态,则可以将其分配给其他线程使用。
虽然delete使用起来是很方便的,但是多了解一下底层的执行过程,可以深刻的理解这个使用规则,运用起来也更加灵活自由。
以下是跟踪到的内部实现代码,可以参考学习一下:
void operator delete(void *pUserData)//pUserData就是delete pUserData的指针
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)return;//检查空指针你
_mlock(_HEAP_LOCK); /* 阻塞其他线程,锁定线程堆,互斥访问 */
__TRY
/* 获取指向内存块其实地址指针 */
pHead = pHdr(pUserData);
/* 验证内存块的类型,验证内存块是否有效 */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* 释放线程堆,其他线程可以访问了 */
__END_TRY_FINALLY
return;
}