• 简析quakeIII中利用链表实现的内存管理(1)


      因为工作主要环境是单片机,所以平时很少使用链表。偶然看到quakeIII源码中有使用链表实现的内存分配的内容,特别摘出自己感兴趣的地方来并添加简短的注释。目前只对malloc的地方增加汉字说明,理解了malloc,其他地方也就自然理解了。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include<windows.h>
      5 
      6 #define ZONEID 0x1d4a11
      7 #define MINFRAGMENT 64
      8 #define MAX_MALLOC    (1024*5)
      9 typedef enum {
     10     TAG_FREE,
     11     TAG_GENERAL,
     12     TAG_BOTLIB,
     13     TAG_RENDERER,
     14     TAG_SMALL,
     15     TAG_STATIC
     16 }memtag_t;
     17 typedef struct memblock_s{
     18     int size;        // including the header and possibly tiny fragments
     19     int tag;        // a tag of 0 is a free block
     20     struct memblock_s *next,*prev;
     21     int id;        // should be ZONEID
     22 }memblock_t;
     23 
     24 typedef struct {
     25     int size;       // total bytes malloced, including header
     26     int used;        // total bytes used
     27     memblock_t blocklist;     // start / end cap for linked list
     28     memblock_t *rover;
     29 }memzone_t;
     30 
     31 // main zone for all "dynamic" memory allocation
     32 memzone_t *mainzone;
     33 // we also have a small zone for small allocations that would only
     34 // fragment the main zone (think of cvar and cmd strings)
     35 memzone_t *smallzone;
     36 /*
     37 ========================
     38 Z_CheckHeap
     39 ========================
     40 */
     41 void Z_CheckHeap(void) {
     42     memblock_t *block;
     43 
     44     for(block = mainzone->blocklist.next;;block = block->next) {
     45         if(block->next == &mainzone->blocklist)
     46         {
     47             break;
     48         }
     49         if ( (unsigned char *)block + block->size != (unsigned char *)block->next)
     50         {
     51             printf("Z_CheckHeap: block size dose not touch the next block
    ");
     52             exit(-1);
     53         }
     54         if ( block->next->prev != block) {
     55             printf( "Z_CheckHeap: next block dosen't have proper back link
    ");
     56             exit(-1);
     57         }
     58         if ( !block->tag && !block->next->tag ) {
     59             printf( "Z_CheckHeap: two consective free blocks
    ");
     60         }
     61     }    
     62 }
     63 /*
     64 ========================
     65 Z_ClearZone
     66 ========================
     67 */
     68 void Z_ClearZone( memzone_t *zone,int size){
     69     memblock_t *block;
     70 
     71     //set the entire zone to one free block;
     72     
     73     zone->blocklist.next = zone->blocklist.prev = block =
     74         ( memblock_t *)((unsigned char *)zone + sizeof(memzone_t));
     75     zone->blocklist.tag = 1;
     76     zone->blocklist.id = 0;
     77     zone->blocklist.size = 0;
     78     zone->rover = block;
     79     zone->size = size;
     80     zone->used = 0;
     81 
     82     block->prev = block->next = &zone->blocklist;
     83     block->tag = 0;
     84     block->id = ZONEID;
     85     block->size = size - sizeof(memzone_t);
     86 }
     87 /*
     88 ========================
     89 Z_AvailableZoneMemory
     90 ========================
     91 */
     92 int Z_AvailableZoneMemory( memzone_t *zone)
     93 {
     94     return zone->size - zone->used;
     95 }
     96 /*
     97 ========================
     98 Z_AvailableMemory
     99 ========================
    100 */
    101 int Z_AvailableMemory( void ){
    102     return Z_AvailableZoneMemory( mainzone);
    103 }
    104 /*
    105 ========================
    106 Z_Free
    107 ========================
    108 */
    109 void Z_Free(void *ptr){
    110     memblock_t *block,*other;
    111     memzone_t *zone;
    112 
    113     if( !ptr){
    114         printf("Z_Free: NULL pointer
    ");
    115         exit(-1);
    116     }
    117     //根据起始指针向前移动sizeof(memblock)
    118     block = (memblock_t *)((unsigned char *)ptr - sizeof(memblock_t));
    119     if (block->id != ZONEID){
    120         printf("Z_Free: freed a pointer without ZONEID
    ");
    121         exit(-1);
    122     }
    123     if (block->tag == 0){
    124         printf("Z_Free: freed a freed pointer
    ");
    125         exit(-1);
    126     }
    127 
    128     if (block->tag == TAG_STATIC){
    129         return;
    130     }
    131 
    132     if ( *(int *)((unsigned char *)block + block->size -4) != ZONEID){
    133         printf("Z_Free: memory block wrote past end
    ");
    134         exit(-1);
    135     }
    136 
    137     if (block->tag == TAG_SMALL){
    138         zone = smallzone;
    139     } else {
    140         zone = mainzone;
    141     }
    142 
    143     zone->used -= block->size;
    144     //set the block to something that should cause problems
    145     //if it is referenced..
    146     memset( ptr, 0xaa, block->size - sizeof( *block ) );
    147 
    148     block->tag = 0;// mark as free
    149 
    150     other = block->prev;
    151     if (!other->tag){
    152         //merge with previous free block
    153         other->size += block->size;
    154         other->next = block->next;
    155         other->next->prev = other;
    156         if (block == zone->rover) {
    157             zone->rover = other;
    158         }
    159         block = other;
    160     }
    161 
    162     zone->rover = block;
    163 
    164     other = block->next;
    165     if ( !other->tag ) {
    166         // merge the next free block onto the end
    167         block->size += other->size;
    168         block->next = other->next;
    169         block->next->prev = block;
    170         if (other == zone->rover) {
    171             zone->rover = block;
    172         }
    173     }
    174 }
    175 /*
    176 ================
    177 Z_FreeTags
    178 ================
    179 */
    180 void Z_FreeTags(int tag) {
    181     int count;
    182     memzone_t *zone;
    183 
    184     if (tag == TAG_SMALL) {
    185         zone = smallzone;
    186     }else {
    187         zone = mainzone;
    188     }
    189     count = 0;
    190 
    191     //use the rover as our pointer,because
    192     //Z_Free automatically adjusts it
    193     zone->rover = zone->blocklist.next;
    194     do{
    195         if( zone->rover->tag == tag) {
    196             count ++;
    197             Z_Free( (void*)(zone->rover +1));
    198             continue;
    199         }
    200         zone->rover = zone->rover->next;
    201     }while(zone->rover != &zone->blocklist);
    202 }
    203 /*
    204 ================
    205 Z_TagMalloc
    206 ================
    207 */
    208 void *Z_TagMalloc( int size, int tag ){
    209     int extra,allocSize,i=20;
    210     memblock_t *start, *rover, *new, *base;
    211     memzone_t *zone;
    212 
    213     if (!tag){
    214         printf("Z_TagMalloc: tried to use a 0 tag
    ");
    215         exit(-1);
    216     }
    217 
    218     if( tag== TAG_SMALL){
    219         zone = smallzone;
    220     }else {
    221         zone = mainzone;
    222     }
    223 
    224     allocSize = size;
    225     //
    226     //scan through the block list looking for the first free block
    227     //of sufficient size
    228     //
    229     size += sizeof(memblock_t);
    230     size += 4;
    231     size = (size +3)& ~3;//align to 32 bit boudary
    232 
    233     base = rover = zone->rover;
    234     start = base->prev;
    235 
    236     do {
    237         if (rover == start ) {
    238             printf( "Z_Malloc: failed on allocation of %i bytes from the %s zone
    ",
    239                         size, zone == smallzone ? "small" : "main");
    240             return NULL;
    241         }
    242         if (rover->tag){//已经在用,则更新base指针
    243             base = rover = rover->next;
    244         } else {//不存在连续的未使用区域
    245             rover = rover->next;
    246         }
    247     }while (base->tag || base->size < size);//查找符合条件的区域
    248 
    249     //
    250     //found a block big enough
    251     //
    252 
    253     extra = base->size - size;
    254     if (extra > MINFRAGMENT) {
    255         // there will be a free fragment after the allocated block
    256         new = ( memblock_t *)((unsigned char *)base + size);
    257         new->size = extra;
    258         new->tag = 0;
    259         new->prev = base;//链表插入
    260         new->id = ZONEID;
    261         new->next = base->next;//链表插入
    262         new->next->prev = new;//链表插入
    263         base->next = new;//已分配区域更新
    264         base->size = size;//已分配区域更新
    265     }
    266 
    267     base->tag = tag;//已分配区域更新
    268 
    269     zone->rover = base->next;//zone更新,指向new
    270     zone->used += base->size;//zone更新,使用计算
    271 
    272     base->id = ZONEID;//已分配区域更新
    273 
    274     *(int *)((unsigned char *)base + base->size - 4) = ZONEID;//尾部错误检验
    275 
    276     return (void *)((unsigned char *)base + sizeof(memblock_t));
    277 }
    278 /*
    279 ========================
    280 Z_Malloc
    281 ========================
    282 */
    283 void *Z_Malloc( int size) {
    284     void *buf;
    285 
    286     Z_CheckHeap();
    287     buf = Z_TagMalloc( size, TAG_GENERAL );
    288     if(buf)
    289     memset( buf, 0, size );
    290 
    291     return buf;
    292 }
    293 
    294 void *S_Malloc( int size ) {
    295     return Z_TagMalloc(size, TAG_SMALL );
    296 }
    297 
    298 void Com_InitZoneMemory( void ) {
    299     mainzone = calloc( MAX_MALLOC, 1 );
    300     if(!mainzone) {
    301         printf("Zone Data failed to allocate %i megs
    ",MAX_MALLOC/(1024*1024));
    302         exit(-1);
    303     }
    304     Z_ClearZone( mainzone, MAX_MALLOC);
    305 }
    306 
    307 
    308 //===============
    309 //test malloc
    310 //===============
    311 int main(void)
    312 {
    313     const char str[] = "kkkkkk
    ";
    314     char *p1,*p2,*p3,*p4,*p5,*p6;
    315     Com_InitZoneMemory();
    316     printf("Available Memory is: %d
    ",Z_AvailableMemory());        
    317     if(1)
    318     {
    319         p1 = Z_Malloc(1024);
    320         printf("P1 Available Memory is: %d,
    ",Z_AvailableMemory());
    321         p2 = Z_Malloc(1024);
    322         printf("P2 Available Memory is: %d
    ",Z_AvailableMemory());
    323         p3 = Z_Malloc(1024);
    324         printf("P3 Available Memory is: %d
    ",Z_AvailableMemory());
    325         p4 = Z_Malloc(1024);
    326         printf("P4 Available Memory is: %d,
    ",Z_AvailableMemory());
    327         p5 = Z_Malloc(1024);
    328         printf("P5 Available Memory is: %d
    ",Z_AvailableMemory());
    329         Z_Free(p2);
    330         printf("P2 Clear Memory is: %d
    ",Z_AvailableMemory());
    331         Z_Free(p3);
    332         printf("P3 Clear Memory is: %d
    ",Z_AvailableMemory());
    333         p6 = Z_Malloc(1024*2);
    334         printf("P3 Available Memory is: %d
    ",Z_AvailableMemory());
    335         //Z_Free(p1);
    336         //printf("P1 Clear Memory is: %d
    ",Z_AvailableMemory());
    337         //Z_Free(p2);
    338         //printf("P2 Clear Memory is: %d
    ",Z_AvailableMemory());
    339         //Z_Free(p3);
    340         //printf("P3 Clear Memory is: %d
    ",Z_AvailableMemory());
    341         getchar();
    342     }
    343     return 0;
    344 }

      在VS中进行了测试,运行的很好。但是内存碎片仍是不可避免,需要特别注意。

  • 相关阅读:
    redis安装
    查看数据库
    redis启动出错Creating Server TCP listening socket 127.0.0.1:6379: bind: No error
    java 面向对象基础
    SpringBoot简单公共返回类
    swift闭包_002_swift闭包
    swift的函数类型_001_swift函数类型基本使用
    swift函数_11_函数的嵌套使用
    swift函数_10_swift中函数基本使用
    swift可选类型_09_optional基本使用
  • 原文地址:https://www.cnblogs.com/duanyongzhen/p/4600426.html
Copyright © 2020-2023  润新知