简析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\n");
 52             exit(-1);
 53         }
 54         if ( block->next->prev != block) {
 55             printf( "Z_CheckHeap: next block dosen't have proper back link\n");
 56             exit(-1);
 57         }
 58         if ( !block->tag && !block->next->tag ) {
 59             printf( "Z_CheckHeap: two consective free blocks\n");
 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\n");
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\n");
121         exit(-1);
122     }
123     if (block->tag == 0){
124         printf("Z_Free: freed a freed pointer\n");
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\n");
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\n");
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\n",
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\n",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\n";
314     char *p1,*p2,*p3,*p4,*p5,*p6;
315     Com_InitZoneMemory();
316     printf("Available Memory is: %d\n",Z_AvailableMemory());        
317     if(1)
318     {
319         p1 = Z_Malloc(1024);
320         printf("P1 Available Memory is: %d,\n",Z_AvailableMemory());
321         p2 = Z_Malloc(1024);
322         printf("P2 Available Memory is: %d\n",Z_AvailableMemory());
323         p3 = Z_Malloc(1024);
324         printf("P3 Available Memory is: %d\n",Z_AvailableMemory());
325         p4 = Z_Malloc(1024);
326         printf("P4 Available Memory is: %d,\n",Z_AvailableMemory());
327         p5 = Z_Malloc(1024);
328         printf("P5 Available Memory is: %d\n",Z_AvailableMemory());
329         Z_Free(p2);
330         printf("P2 Clear Memory is: %d\n",Z_AvailableMemory());
331         Z_Free(p3);
332         printf("P3 Clear Memory is: %d\n",Z_AvailableMemory());
333         p6 = Z_Malloc(1024*2);
334         printf("P3 Available Memory is: %d\n",Z_AvailableMemory());
335         //Z_Free(p1);
336         //printf("P1 Clear Memory is: %d\n",Z_AvailableMemory());
337         //Z_Free(p2);
338         //printf("P2 Clear Memory is: %d\n",Z_AvailableMemory());
339         //Z_Free(p3);
340         //printf("P3 Clear Memory is: %d\n",Z_AvailableMemory());
341         getchar();
342     }
343     return 0;
344 }

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

posted @ 2015-06-25 17:18  still_waters  阅读(222)  评论(0编辑  收藏  举报