free()函数到底做了什么?(第二问)
原帖
(原帖回答了的朋友建议来这里报个到~好给分)
首先,感谢各位的解答;
其次,我还是有2个问题:
1》
7楼的大大 说 “不一定不变,free,malloc后可以使两个空闲空间合并,里面有标识的分配情况记录”,貌似这和大部分亲说的有区别啊,到底怎么回事?各位有没有仔细看到这句话?斟酌一下
2》
free()释放内存的大小是怎么判定的?
释放一块连续的内存需要2个要素:首地址,内存大小;首地址可以根据 free(str)的参数str确定,那内存大小呢?是malloc()时就已经记录下来的?
[解决办法]
其实可以统一起来理解,memory有一套管理机制,不同平台上的具体实现会由差别。不过总体上来说,malloc时就会记录相关的要素,你可以简单理解为头信息,它的寻址会与返回的指针相关联,所以不用担心free会找不到。
[解决办法]
给你举个例子
假如你家户口本上写着:你家地址是 XX大街,XX小区,10# 3单元,3楼1号
这时候,突然来了一帮流氓,把 XX大街,XX小区,10# 3单元,3楼1号 给拆没了。那你说你家户口本上的地址会自己变没了么?
str 就是户口本,那块内存就是你家。
[解决办法]
1.free根据你malloc分配的内存大小会有相应的释放策略。
2.有一个cookie记录分配的大小的。
[解决办法]
free其实只是置了个废弃标志
[解决办法]
可以参考Linux源代码中malloc和free对应的源代码。
[解决办法]
看看malloc做了些什么,free做相反 的操作即可
- C/C++ code
/*** *malloc.c - Get a block of memory from the heap * * Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved. * *Purpose: * Defines the malloc() function. * *******************************************************************************/ #include <cruntime.h> #include <malloc.h> #include <internal.h> #include <mtdll.h> #include <dbgint.h> #ifdef WINHEAP #include <windows.h> #include <winheap.h> #else /* WINHEAP */ #include <heap.h> #endif /* WINHEAP */ extern int _newmode; /* malloc new() handler mode */ /*** *void *malloc(size_t size) - Get a block of memory from the heap * *Purpose: * Allocate of block of memory of at least size bytes from the heap and * return a pointer to it. * * Calls the new appropriate new handler (if installed). * *Entry: * size_t size - size of block requested * *Exit: * Success: Pointer to memory block * Failure: NULL (or some error value) * *Uses: * *Exceptions: * *******************************************************************************/ void * __cdecl _malloc_base (size_t size) { return _nh_malloc_base(size, _newmode); } /*** *void *_nh_malloc_base(size_t size) - Get a block of memory from the heap * *Purpose: * Allocate of block of memory of at least size bytes from the heap and * return a pointer to it. * * Calls the appropriate new handler (if installed). * * There are two distinct new handler schemes supported. The 'new' ANSI * C++ scheme overrides the 'old' scheme when it is activated. A value of * _NOPTH for the 'new' handler indicates that it is inactivated and the * 'old' handler is then called. * *Entry: * size_t size - size of block requested * *Exit: * Success: Pointer to memory block * Failure: NULL (or some error value) * *Uses: * *Exceptions: * *******************************************************************************/ void * __cdecl _nh_malloc_base (size_t size, int nhFlag) { void * pvReturn; // validate size if (size > _HEAP_MAXREQ) return NULL; #ifndef WINHEAP /* round requested size */ size = _ROUND2(size, _GRANULARITY); #endif /* WINHEAP */ for (;;) { // allocate memory block if (size <= _HEAP_MAXREQ) pvReturn = _heap_alloc_base(size); else pvReturn = NULL; // if successful allocation, return pointer to memory // if new handling turned off altogether, return NULL if (pvReturn || nhFlag == 0) return pvReturn; // call installed new handler if (!_callnewh(size)) return NULL; // new handler was successful -- try to allocate again } } /*** *void *_heap_alloc_base(size_t size) - does actual allocation * *Purpose: * Same as malloc() except the new handler is not called. * *Entry: * See malloc * *Exit: * See malloc * *Exceptions: * *******************************************************************************/ void * __cdecl _heap_alloc_base (size_t size) { #ifdef WINHEAP void * pvReturn; #else /* WINHEAP */ _PBLKDESC pdesc; _PBLKDESC pdesc2; #endif /* WINHEAP */ #ifdef WINHEAP if (size <= __sbh_threshold) { _mlock(_HEAP_LOCK); pvReturn = __sbh_alloc_block(size); _munlock(_HEAP_LOCK); if (pvReturn) return pvReturn; } if (size == 0) size = 1; size = (size + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1); return HeapAlloc(_crtheap, 0, size); } #else /* WINHEAP */ /* try to find a big enough free block */ if ( (pdesc = _heap_search(size)) == NULL ) { if ( _heap_grow(size) != -1 ) { /* try finding a big enough free block again. the * success of the call to _heap_grow should guarantee * it, but... */ if ( (pdesc = _heap_search(size)) == NULL ) { /* something unexpected, and very bad, has * happened. abort! */ _heap_abort(); } } else return NULL; } /* carve the block into two pieces (if necessary). the first piece * shall be of the exact requested size, marked inuse and returned to * the caller. the leftover piece is to be marked free. */ if ( _BLKSIZE(pdesc) != size ) { /* split up the block and free the leftover piece back to * the heap */ if ( (pdesc2 = _heap_split_block(pdesc, size)) != NULL ) _SET_FREE(pdesc2); } /* mark pdesc inuse */ _SET_INUSE(pdesc); /* check proverdesc and reset, if necessary */ _heap_desc.proverdesc = pdesc->pnextdesc; return( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) ); } /*** *_PBLKDESC _heap_split_block(pdesc, newsize) - split a heap allocation block * into two allocation blocks * *Purpose: * Split the allocation block described by pdesc into two blocks, the * first one being of newsize bytes. * * Notes: It is caller's responsibilty to set the status (i.e., free * or inuse) of the two new blocks, and to check and reset proverdesc * if necessary. See Exceptions (below) for additional requirements. * *Entry: * _PBLKDESC pdesc - pointer to the allocation block descriptor * size_t newsize - size for the first of the two sub-blocks (i.e., * (i.e., newsize == _BLKSIZE(pdesc), on exit) * *Exit: * If successful, return a pointer to the descriptor for the leftover * block. * Otherwise, return NULL. * *Exceptions: * It is assumed pdesc points to a valid allocation block descriptor and * newsize is a valid heap block size as is (i.e., WITHOUT rounding). If * either of these of assumption is violated, _heap_split_block() will * likely corrupt the heap. Note also that _heap_split_block will simply * return to the caller if newsize >= _BLKSIZE(pdesc), on entry. * *******************************************************************************/ _PBLKDESC __cdecl _heap_split_block ( REG1 _PBLKDESC pdesc, size_t newsize ) { REG2 _PBLKDESC pdesc2; _ASSERTE(("_heap_split_block: bad pdesc arg", _CHECK_PDESC(pdesc))); _ASSERTE(("_heap_split_block: bad newsize arg", _ROUND2(newsize,_GRANULARITY) == newsize)); /* carve the block into two pieces (if possible). the first piece * is to be exactly newsize bytes. */ if ( (_BLKSIZE(pdesc) > newsize) && ((pdesc2 = __getempty()) != NULL) ) { /* set it up to manage the second piece and link it in to * the list */ pdesc2->pblock = (void *)((char *)_ADDRESS(pdesc) + newsize + _HDRSIZE); *(void **)(pdesc2->pblock) = pdesc2; pdesc2->pnextdesc = pdesc->pnextdesc; pdesc->pnextdesc = pdesc2; return pdesc2; } return NULL; } #endif /* WINHEAP */
[解决办法]
[解决办法]
- C/C++ code
/****free.c - free an entry in the heap** Copyright (c) Microsoft Corporation. All rights reserved.**Purpose:* Defines the following functions:* free() - free a memory block in the heap********************************************************************************/#include <cruntime.h>#include <malloc.h>#include <winheap.h>#include <windows.h>#include <internal.h>#include <mtdll.h>#include <dbgint.h>#include <rtcsup.h>/****void free(pblock) - free a block in the heap**Purpose:* Free a memory block in the heap.** Special ANSI Requirements:** (1) free(NULL) is benign.**Entry:* void *pblock - pointer to a memory block in the heap**Return:* <void>********************************************************************************/void __cdecl _free_base (void * pBlock){ int retval = 0; if (pBlock == NULL) return; RTCCALLBACK(_RTC_Free_hook, (pBlock, 0)); retval = HeapFree(_crtheap, 0, pBlock); if (retval == 0) { errno = _get_errno_from_oserr(GetLastError()); }}
[解决办法]
他是对堆栈内存管理的外层封装:
真实的实现你是看不到的,
只要能知道这个东西最终实现了什么就好,
实际上真正的都在那三个DLL中,楼主以后水平高了,
可以尝试着做点什么……
[解决办法]