您的位置:首页 > 编程语言 > C语言/C++

深入理解malloc函数(c语言)

2011-04-28 19:25 387 查看
看下面代码(来自vs2005)

深度解析malloc函数:
extern "C" _CRTIMP void * __cdecl malloc (
size_t nSize
)
{
void *res = _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);//函数调用,跟进
//#define _NORMAL_BLOCK    1
//_newmode == 0

RTCCALLBACK(_RTC_Allocate_hook, (res, nSize, 0));

return res;
}

//_nh_malloc_dbg函数
extern "C" void * __cdecl _nh_malloc_dbg (
size_t nSize,
int nhFlag,
int nBlockUse,
const char * szFileName,
int nLine
)
{
void * pvBlk;

for (;;)
{
/* do the allocation
*/
pvBlk = _heap_alloc_dbg(nSize, nBlockUse, szFileName, nLine); //调用函数_heap_alloc_dbg,跟进

if (pvBlk)
{
return pvBlk;
}
if (nhFlag == 0)
{
errno = ENOMEM;
return pvBlk;
}

/* call installed new handler */
if (!_callnewh(nSize))
{
errno = ENOMEM;
return NULL;
}

/* new handler was successful -- try to allocate again */
}
}

//_heap_alloc_dbg函数
extern "C" void * __cdecl _heap_alloc_dbg(
size_t nSize,
int nBlockUse,
const char * szFileName,
int nLine
)
{
long lRequest;
size_t blockSize;
int fIgnore = FALSE;
_CrtMemBlockHeader * pHead;
void *retval=NULL;

/* lock the heap
*/
_mlock(_HEAP_LOCK);
__try {

/* verify heap before allocation */
if (check_frequency > 0)
if (check_counter == (check_frequency - 1))
{
_ASSERTE(_CrtCheckMemory());
check_counter = 0;
}
else
check_counter++;

lRequest = _lRequestCurr;

/* break into debugger at specific memory allocation */
if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)
_CrtDbgBreak();

/* forced failure */
if ((_pfnAllocHook) && !(*_pfnAllocHook)(_HOOK_ALLOC, NULL, nSize, nBlockUse, lRequest, (const unsigned char *)szFileName, nLine))
{
if (szFileName)
_RPT2(_CRT_WARN, "Client hook allocation failure at file %hs line %d./n",
szFileName, nLine);
else
_RPT0(_CRT_WARN, "Client hook allocation failure./n");
}
else
{
/* cannot ignore CRT allocations */
if (_BLOCK_TYPE(nBlockUse) != _CRT_BLOCK &&
!(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF))
fIgnore = TRUE;

/* Diagnostic memory allocation from this point on */

if (nSize > (size_t)(_HEAP_MAXREQ - nNoMansLandSize - sizeof(_CrtMemBlockHeader)))
{
_RPT1(_CRT_ERROR, "Invalid allocation size: %Iu bytes./n", nSize);
errno = ENOMEM;
}
else
{
if (!_BLOCK_TYPE_IS_VALID(nBlockUse))
{
_RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type./n");
}

blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;//实际内存分配的大小

#ifndef WINHEAP
/* round requested size */
blockSize = _ROUND2(blockSize, _GRANULARITY);
#endif  /* WINHEAP */

RTCCALLBACK(_RTC_FuncCheckSet_hook,(0));
pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize);

if (pHead == NULL)
{
errno = ENOMEM;
RTCCALLBACK(_RTC_FuncCheckSet_hook,(1));
}
else
{

/* commit allocation */
++_lRequestCurr;

if (fIgnore)
{
//这里应该是所有申请的空间了,包括信息节点
pHead->pBlockHeaderNext = NULL;
pHead->pBlockHeaderPrev = NULL;
pHead->szFileName = NULL;
pHead->nLine = IGNORE_LINE;
pHead->nDataSize = nSize;
pHead->nBlockUse = _IGNORE_BLOCK;
pHead->lRequest = IGNORE_REQ;
}
else {
/* keep track of total amount of memory allocated */
_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;
}

/* fill in gap before and after real block */
//+		pHead	0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...}	_CrtMemBlockHeader *
memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize);
//+		pHead	0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...}	_CrtMemBlockHeader *
memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize);
//>+		pHead	0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...}	_CrtMemBlockHeader *

/* fill data with silly value (but non-zero) */
memset((void *)pbData(pHead), _bCleanLandFill, nSize);
//+		pHead	0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...}	_CrtMemBlockHeader *
RTCCALLBACK(_RTC_FuncCheckSet_hook,(1));

retval=(void *)pbData(pHead);
//+		pHead	0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...}	_CrtMemBlockHeader *
//		retval	0x003f8270	void *

}
}
}

}
__finally {
/* unlock the heap
*/
_munlock(_HEAP_LOCK);
}
return retval;
}


根据代码,我们可以知道,malloc申请的空间不只是nSize大小,还有一个用来记录以申请空间信息的头,这样,总的大小就是blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize。这就解释了为什么free的时候只需要传入指针就行。

可以尝试一下代码:

int _tmain(int argc, _TCHAR* argv[])
{
int *p=NULL;
p=(int*)malloc(sizeof(int)*20);
printf("%d/n",*(p-1));
printf("%d/n",*(p-2));
printf("%d/n",*(p-3));
printf("%d/n",*(p-4));
}


*(p-4)的值就是malloc时的size大小。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: