看csapp写内存分配器
目标:实现一个放置策略为首次适配,并合策略为立即并合基于隐式空闲链表的内存分配器。
这里使用memlib.c包提供的存储器系统模型,该模型允许我们在不干涉已存在的malloc包的情况下运行分配器,也就是说封装了malloc函数。
memlib.h
void mem_init(void); void *mem_sbrk(int incr);
memlib.c:(封装了malloc函数)
#include <stdio.h> #include <stdlib.h> #include "csapp.h" #define MAX_HEAP (1 << 30) static char *mem_heap; /* Points to first byte of heap */ static char *mem_brk; /* Points to last byte of heap plus 1 */ static char *mem_max_addr; /* Max legal heap addr plus 1*/ void mem_init(void) { mem_heap = (char *)Malloc(MAX_HEAP); mem_brk = (char *)mem_heap; mem_max_addr = (char *)(mem_heap + MAX_HEAP); } /* * mem_sbrk - Simple model of the sbrk function. Extends the heap * by incr bytes and returns the start address of the new area. In * this model, the heap cannot be shrunk. */ void *mem_sbrk(int incr) { char *old_brk = mem_brk; if ( (incr < 0) || ((mem_brk + incr) > mem_max_addr)) { errno = ENOMEM; fprintf(stderr, "ERROR: mem_sbrk failed. Ran out of memory...\n"); return (void *)-1; } mem_brk += incr; return (void *)old_brk; }
mm.h
/************************************************************************* > File Name: mm.h > Author: connan_d > Mail: [email protected] > Created Time: 2015年05月07日 星期四 10时40分49秒 > 定义了内存分配器的接口 ************************************************************************/ int mm_init(); //初始化 void *mm_malloc(size_t size); //分配内存 void mm_free(void *bp); //回收内存
mm.c
/************************************************************************* > File Name: mm.c > Author: connan_d > Mail: [email protected] > Created Time: 2015年05月07日 星期四 10时50分51秒 ************************************************************************/ #include<stdio.h> #include "mm.h" #include "memlib.h" static void *extend_heap(size_t words); //拓展堆的可用空间,返回原堆顶地址(mem_brk),失败返回NULL static void *coalesce(void *bp); //并合bp指向块的前后块,返回并合后的块指针 static void *find_fit(size_t size); //寻找第一个空间大于size的空闲块,返回其地址,未找到时,返回NULL static void place(void *bp, size_t asize); //分割find_fit返回的块,创建块结构 //宏定义 #define WSIZE 4 #define DSIZE 8 #define CHUNKSIZE (1<<12) //每次拓展堆的大小 #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define PACK(size, alloc) ((size) | (alloc)) //将块大小和标志位整合到一个字中 #define GET(p) (*(unsigned int *)(p)) //返回p指向的字 #define PUT(p, val) (*(unsigned int *)(p) = (val)) //将值压入p指向的字 #define GET_SIZE(p) (GET(p) & ~0x7) //返回头或尾部的高29位,即该块的大小 #define GET_ALLOC(p) (GET(p) & 0x1) //返回标志位 #define HDRP(bp) ((char *)bp - WSIZE) //返回块的头部 #define FTRP(bp) ((char *)bp + GET_SIZE(bp) - DSIZE) //返回块的尾部 #define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE((char *)bp - WSIZE)) //当前当块的下一块 #define PREV_BLKP(bp) ((char *)bp - GET_SIZE((char *)bp - DSIZE)) //返回但前块的上一块 static void *heap_listp; //指向第一个块(序言块) //接口 int mm_init(void) //初始化,成功返回0,失败返回 { mem_init(); if ( (heap_listp = mem_sbrk(4 * WSIZE)) == (void *)-1) return -1; PUT(heap_listp, 0); PUT(heap_listp + WSIZE, PACK(8, 1)); //序言块头部 PUT(heap_listp + 2*WSIZE, PACK(8, 1)); //序言块尾部 PUT(heap_listp + 3*WSIZE, PACK(0, 1)); //结尾块 heap_listp += 2*WSIZE; if (extend_heap(CHUNKSIZE/WSIZE) == NULL) return -1; return 0; } void mm_free(void *bp) //释放bp指向块的内存 { size_t size = GET_SIZE(HDRP(bp)); PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size, 0)); coalesce(bp); //并合前后块 } void *mm_malloc(size_t size) //分配size字节大小的块,返回指向块的指针 { size_t asize; //调整过的size size_t extendsize; void *bp; if (size == 0) return NULL; if (size < DSIZE) asize = 2 * DSIZE; else asize = DSIZE * ((size + (DSIZE) + (DSIZE - 1)) / DSIZE); if ( (bp = find_fit(asize)) != NULL) { place(bp, asize); return bp; } extendsize = MAX(asize, CHUNKSIZE); if ( (bp = extend_heap(extendsize/WSIZE)) == NULL ) return NULL; place(bp, asize); return bp; } //工具函数定义 static void *extend_heap(size_t words) //拓展堆的可用空间,返回原堆顶地址(mem_brk),失败返回NULL { char *bp; size_t size; size = (words % 2) ? (words + 1) * WSIZE : words * WSIZE; //保持双字对齐 if ((long)(bp = mem_sbrk(size)) == -1) return NULL; PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size, 0)); PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); return (void *)bp; } static void *coalesce(void *bp) //并合bp指向块的前后块,返回并合后的块指针 { size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(bp))); //上一块是否分配 size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); //下一块是否分配 size_t size; if (prev_alloc && next_alloc) { return bp; } else if (prev_alloc && !next_alloc) { size += GET_SIZE(HDRP(NEXT_BLKP(bp))); PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size,0)); } else if (!prev_alloc && next_alloc) { size += GET_SIZE(HDRP(PREV_BLKP(bp))); PUT(FTRP(bp), PACK(size, 0)); PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); bp = PREV_BLKP(bp); } else { size += GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(FTRP(NEXT_BLKP(bp))); PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); PUT(FTRP(NEXT_BLKP(bp)), PACK(size, 0)); bp = PREV_BLKP(bp); } return bp; } static void *find_fit(size_t size) //寻找第一个空间大于size的空闲块,返回其地址,未找到时,返回NULL { void *bp; for (bp = heap_listp; GET_SIZE(bp) > 0; bp = NEXT_BLKP(bp)) { if (GET_SIZE(HDRP(bp)) >= size && GET_ALLOC(HDRP(bp)) != 1) //返回第一块未分配且空间大于size的空闲块 return bp; } return NULL; } static void place(void *bp, size_t asize) //分割find_fit返回的块,创建块结构 { size_t bsize = GET_SIZE(HDRP(bp)); if ( (bsize - asize) > 2*DSIZE ) //最小块为16字节,分割块 { PUT(HDRP(bp), PACK(asize, 1)); PUT(FTRP(bp), PACK(asize, 1)); bp = NEXT_BLKP(bp); PUT(HDRP(bp), PACK(bsize - asize, 0)); PUT(FTRP(bp), PACK(bsize - asize, 0)); } else //不用分割 { PUT(HDRP(bp), PACK(asize, 1)); PUT(FTRP(bp), PACK(asize, 1)); } }
mmTest.c
/************************************************************************* > File Name: mmTest.c > Author: connan_d > Mail: [email protected] > Created Time: 2015年05月07日 星期四 14时23分30秒 ************************************************************************/ #include<stdio.h> #include "mm.h" int main() { mem_init(); //初始化模型 mm_init(); //初始化分配器 int *a = mm_malloc(sizeof(int)); //测试int *a = 1; char *b = mm_malloc(sizeof(char)); //测试char *b = 'z'; double *c = mm_malloc(sizeof(double)); //测试double *c = 2.0; printf("a = %d\nb = %c\nc = %f\n", *a, *b, *c); }
编译链接时需要csapp.h头文件:gcc -o mmtest mmTest.c mm.c memlib.c -lpthread
结果:
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。