首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

free()函数终究做了什么?(第二问)

2012-08-17 
free()函数到底做了什么?(第二问)原帖(原帖回答了的朋友建议来这里报个到~好给分)首先,感谢各位的解答;其

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 */ 


[解决办法]

探讨

可以参考Linux源代码中malloc和free对应的源代码。

[解决办法]
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中,楼主以后水平高了,
可以尝试着做点什么……
[解决办法]
探讨
额,谢谢2楼的大大,再问:
1.学了 操作系统 能懂这套机制么?(回答 能 或 不能 即可)
2.您的签名好有个性,有兴趣解释下么?(如果这不算个人隐私的话)

热点排行