因为工作主要环境是单片机,所以平时很少使用链表。偶然看到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中进行了测试,运行的很好。但是内存碎片仍是不可避免,需要特别注意。