粗解“new”之来龙去脉(二)

来源:互联网 发布:2017店铺淘宝客怎么做 编辑:程序博客网 时间:2024/05/27 16:42
 

接着往下走看看_heap_alloc_base这个函数

#define MAX_ALLOC_DATA_SIZE     0x3f8#define BYTES_PER_PARA      16size_t       __sbh_threshold = MAX_ALLOC_DATA_SIZE;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);}

   

   我们可以看出,如果请求分配的内存大小小等于__sbh_threshold (默认值是0x3f8)的话,则调用__sbh_alloc_block去获得地址,如果大于的话则调用HeapAlloc去分配,其中__sbh_threshold值也是可以设置得,但必需是小于0x3f8的。

int __cdecl _set_sbh_threshold (size_t threshold){    //  test against maximum value - if too large, return error    if (threshold > MAX_ALLOC_DATA_SIZE)        return 0;    //  set the threshold value    __sbh_threshold = threshold;    return 1;}

 

      我们还可以看出如果大小为0的话,会设置size = 1,也就是说如果我们去new一个大小为0的地址也会成功,会自动把它大小设置为1.当然还有一些别的附加内容。
对HeapAlloc的分析不再继续往下进行,因为我找不到它的源代码。我们接着看调用__sbh_alloc_block如何分配。

 

typedef unsigned int    BITVEC;typedef struct tagRegion{    int                 indGroupUse;    char                cntRegionSize[64];    BITVEC              bitvGroupHi[GROUPS_PER_REGION];    BITVEC              bitvGroupLo[GROUPS_PER_REGION];    struct tagGroup     grpHeadList[GROUPS_PER_REGION];}REGION, *PREGION;typedef struct tagHeader{    BITVEC              bitvEntryHi;    BITVEC              bitvEntryLo;    BITVEC              bitvCommit;    void *              pHeapData;    struct tagRegion *  pRegion;}HEADER, *PHEADER;PHEADER      __sbh_pHeaderList;        //  pointer to list startPHEADER      __sbh_pHeaderScan;        //  pointer to list roverint          __sbh_sizeHeaderList;     //  allocated size of listint          __sbh_cntHeaderList;      //  count of entries defined#define BYTES_PER_PARA      16void * __cdecl __sbh_alloc_block (int intSize){    PHEADER     pHeaderLast = __sbh_pHeaderList + __sbh_cntHeaderList;    PHEADER     pHeader;    PREGION     pRegion;    PGROUP      pGroup;    PENTRY      pEntry;    PENTRY      pHead;    BITVEC      bitvEntryLo;    BITVEC      bitvEntryHi;    BITVEC      bitvTest;    int         sizeEntry;    int         indEntry;    int         indGroupUse;    int         sizeNewFree;    int         indNewFree;    //  add 8 bytes entry overhead and round up to next para size    sizeEntry = (intSize + 2 * sizeof(int) + (BYTES_PER_PARA - 1))                                          & ~(BYTES_PER_PARA - 1);    //  determine index and mask from entry size    //  Hi MSB: bit 0      size: 1 paragraph    //          bit 1            2 paragraphs    //          ...              ...    //          bit 30           31 paragraphs    //          bit 31           32 paragraphs    //  Lo MSB: bit 0      size: 33 paragraph    //          bit 1            34 paragraphs    //          ...              ...    //          bit 30           63 paragraphs    //          bit 31           64+ paragraphs    indEntry = (sizeEntry >> 4) - 1;    if (indEntry < 32)    {        bitvEntryHi = 0xffffffffUL >> indEntry;        bitvEntryLo = 0xffffffffUL;    }    else    {        bitvEntryHi = 0;        bitvEntryLo = 0xffffffffUL >> (indEntry - 32);    }    //  scan header list from rover to end for region with a free    //  entry with an adequate size    pHeader = __sbh_pHeaderScan;    while (pHeader < pHeaderLast)    {        if ((bitvEntryHi & pHeader->bitvEntryHi) |            (bitvEntryLo & pHeader->bitvEntryLo))            break;        pHeader++;    }    //  if no entry, scan from list start up to the rover    if (pHeader == pHeaderLast)    {        pHeader = __sbh_pHeaderList;        while (pHeader < __sbh_pHeaderScan)        {            if ((bitvEntryHi & pHeader->bitvEntryHi) |                (bitvEntryLo & pHeader->bitvEntryLo))                break;            pHeader++;        }        //  no free entry exists, scan list from rover to end        //  for available groups to commit        if (pHeader == __sbh_pHeaderScan)        {            while (pHeader < pHeaderLast)            {                if (pHeader->bitvCommit)                    break;                pHeader++;            }            //  if no available groups, scan from start to rover            if (pHeader == pHeaderLast)            {                pHeader = __sbh_pHeaderList;                while (pHeader < __sbh_pHeaderScan)                {                    if (pHeader->bitvCommit)                        break;                    pHeader++;                }                //  if no available groups, create a new region                if (pHeader == __sbh_pHeaderScan)                    if (!(pHeader = __sbh_alloc_new_region()))                        return NULL;            }            //  commit a new group in region associated with pHeader            if ((pHeader->pRegion->indGroupUse =                                    __sbh_alloc_new_group(pHeader)) == -1)                return NULL;        }    }    __sbh_pHeaderScan = pHeader;    pRegion = pHeader->pRegion;    indGroupUse = pRegion->indGroupUse;    //  determine the group to allocate from    if (indGroupUse == -1 ||                    !((bitvEntryHi & pRegion->bitvGroupHi[indGroupUse]) |                      (bitvEntryLo & pRegion->bitvGroupLo[indGroupUse])))    {        //  preferred group could not allocate entry, so        //  scan through all defined vectors        indGroupUse = 0;        while (!((bitvEntryHi & pRegion->bitvGroupHi[indGroupUse]) |                 (bitvEntryLo & pRegion->bitvGroupLo[indGroupUse])))            indGroupUse++;    }    pGroup = &pRegion->grpHeadList[indGroupUse];    //  determine bucket index    indEntry = 0;    //  get high entry intersection - if zero, use the lower one    if (!(bitvTest = bitvEntryHi & pRegion->bitvGroupHi[indGroupUse]))    {        indEntry = 32;        bitvTest = bitvEntryLo & pRegion->bitvGroupLo[indGroupUse];    }       while ((int)bitvTest >= 0)    {           bitvTest <<= 1;           indEntry++;    }    pEntry = pGroup->listHead[indEntry].pEntryNext;    //  compute size and bucket index of new free entry    //  for zero-sized entry, the index is -1    sizeNewFree = pEntry->sizeFront - sizeEntry;    indNewFree = (sizeNewFree >> 4) - 1;    if (indNewFree > 63)        indNewFree = 63;    //  only modify entry pointers if bucket index changed    if (indNewFree != indEntry)    {        //  test entry is sole member of bucket (next == prev),        if (pEntry->pEntryNext == pEntry->pEntryPrev)        {            //  clear bit in group vector, decrement region count            //  if region count is now zero, clear bit in region vector            if (indEntry < 32)            {                pRegion->bitvGroupHi[indGroupUse] &=                                            ~(0x80000000L >> indEntry);                if (--pRegion->cntRegionSize[indEntry] == 0)                    pHeader->bitvEntryHi &= ~(0x80000000L >> indEntry);            }            else            {                pRegion->bitvGroupLo[indGroupUse] &=                                            ~(0x80000000L >> (indEntry - 32));                if (--pRegion->cntRegionSize[indEntry] == 0)                    pHeader->bitvEntryLo &= ~(0x80000000L >> (indEntry - 32));            }        }        //  unlink entry from list        pEntry->pEntryPrev->pEntryNext = pEntry->pEntryNext;        pEntry->pEntryNext->pEntryPrev = pEntry->pEntryPrev;        //  if free entry size is still nonzero, reconnect it        if (sizeNewFree != 0)        {            //  add entry to the start of the bucket list            pHead = (PENTRY)((char *)&pGroup->listHead[indNewFree] -                                                           sizeof(int));            pEntry->pEntryNext = pHead->pEntryNext;            pEntry->pEntryPrev = pHead;            pHead->pEntryNext = pEntry;            pEntry->pEntryNext->pEntryPrev = pEntry;            //  test entry is sole member of bucket (next == prev),            if (pEntry->pEntryNext == pEntry->pEntryPrev)            {                //  if region count was zero, set bit in region vector                //  set bit in group vector, increment region count                if (indNewFree < 32)                {                    if (pRegion->cntRegionSize[indNewFree]++ == 0)                        pHeader->bitvEntryHi |= 0x80000000L >> indNewFree;                    pRegion->bitvGroupHi[indGroupUse] |=                                                0x80000000L >> indNewFree;                }                else                {                    if (pRegion->cntRegionSize[indNewFree]++ == 0)                        pHeader->bitvEntryLo |=                                        0x80000000L >> (indNewFree - 32);                    pRegion->bitvGroupLo[indGroupUse] |=                                        0x80000000L >> (indNewFree - 32);                }            }        }    }    //  change size of free entry (front and back)    if (sizeNewFree != 0)    {        pEntry->sizeFront = sizeNewFree;        ((PENTRYEND)((char *)pEntry + sizeNewFree -                    sizeof(ENTRYEND)))->sizeBack = sizeNewFree;    }    //  mark the allocated entry    pEntry = (PENTRY)((char *)pEntry + sizeNewFree);    pEntry->sizeFront = sizeEntry + 1;    ((PENTRYEND)((char *)pEntry + sizeEntry -                    sizeof(ENTRYEND)))->sizeBack = sizeEntry + 1;    //  one more allocation in group - test if group was empty    if (pGroup->cntEntries++ == 0)    {        //  if allocating into deferred group, cancel deferral        if (pHeader == __sbh_pHeaderDefer &&                                  indGroupUse == __sbh_indGroupDefer)            __sbh_pHeaderDefer = NULL;    }    pRegion->indGroupUse = indGroupUse;    return (void *)((char *)pEntry + sizeof(int));}

 

这个函数使用了一些全局变量需要注意一下,比如使用了__sbh_pHeaderList等,它们的值是什么时候初始化的呢?

原创粉丝点击