堆管理器实现代码,heap.h
#ifndef _HEAP_IMPL_
#define _HEAP_IMPL_
#include <stdio.h>
#include <stdlib.h>
// Basic constants and macros.
#define WSIZE 4 // Word and header/footer size(bytes)
#define DSIZE 8 // Double word size(bytes)
#define CHUNKSIZE (1<<12) // Extend heap by this amount(bytes)
#define MAX(x, y) ((x) > (y)? (x) : (y))
// Pack a size and allocate bit into a word
#define PACK(size, alloc) ((size)|(alloc))
// Read and write a word at addres p
#define GET(p) (*(unsigned int*)(p))
#define PUT(p, val) (*(unsigned int*)(p) = (val))
// Read the size and allocated fields from address p.
#define GET_SIZE(p) (GET(p) & ~0x7)
#define GET_ALLOC(p) (GET(p) & 0x1)
// Given block ptr bp, compute address of its header and footer
#define HDRP(bp) ((char*)(bp)-WSIZE)
#define FTRP(bp) ((char*)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)
// Given block ptr bp, compute address of next and previous blocks.
#define NEXT_BLKP(bp) ((char*)(bp) + GET_SIZE(((char*)(bp) - WSIZE)))
#define PREV_BLKP(bp) ((char*)(bp) - GET_SIZE(((char*)(bp) - DSIZE)))
int mm_init(void);
void mm_free(void *bp);
void* mm_malloc(size_t size);
#endif
heap.c
#include "heap.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
// private glabal variables
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.
static void *heap_listp;
#define MAX_HEAP (16*1024*1024)
static void mem_init(void)
{
mem_heap = (char *)malloc(MAX_HEAP);
if(mem_heap == NULL)
{
fprintf(stderr, "failure to malloc.\n");
return;
}
mem_brk = (char *)mem_heap;
mem_max_addr = (char*)(mem_heap + MAX_HEAP);
}
// mem_sbrk:simple model of the sbrk function. extens 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, run out of memory ...\n");
return (void*)-1;
}
mem_brk += incr;
return (void*)old_brk;
}
static void *coalesce(void *bp)
{
size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t size = GET_SIZE(HDRP(bp));
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;
}
void mm_free(void *bp)
{
size_t size = GET_SIZE(HDRP(bp));
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
coalesce(bp);
}
static void *extend_heap(size_t words)
{
char *bp;
size_t size;
size = (words % 2) ? (words + 1) * WSIZE : words * WSIZE;
if((long)(bp = mem_sbrk(size)) == -1)
{
return NULL;
}
// initialize free block header/footer and the epilogue header. PUT(HDRP(bp), PACK(size, 0));
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1));
// coalesce if the previous block was free.
return coalesce(bp);
}
int mm_init(void)
{
void *bp;
mem_init();
// create the initial empty heap.
if((heap_listp = mem_sbrk(4*WSIZE)) == (void*)-1)
{
return -1;
}
PUT(heap_listp + (0*WSIZE), 0);
PUT(heap_listp + (1*WSIZE), PACK(DSIZE, 1));
PUT(heap_listp + (2*WSIZE), PACK(DSIZE, 1));
PUT(heap_listp + (3*WSIZE), PACK(0, 1));
heap_listp += 2*WSIZE;
if((bp = extend_heap(CHUNKSIZE/WSIZE)) == NULL)
{
fprintf(stderr, "%s line %d, failure.\n", __func__, __LINE__);
return -1;
}
return 0;
}
static void *find_fit(size_t asize)
{
void *bp;
for(bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp=NEXT_BLKP(bp))
{
if(GET_SIZE(HDRP(bp)) >= asize && GET_ALLOC(HDRP(bp))!=1)
{
return bp;
}
}
return NULL;
}
static void place(void *bp, size_t asize)
{
size_t bsize = GET_SIZE(HDRP(bp));
if ((bsize - asize) > 2*DSIZE)
{
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));
}
}
void *mm_malloc(size_t size)
{
size_t asize; // adjusted block size.
size_t extendsize; // amount to extend heap of no fit.
char *bp;
// ignore spurious requests.
if(size == 0)
{
return NULL;
}
if(size <= DSIZE)
{
asize = 2*DSIZE;
}
else
{
asize = DSIZE *((size + (DSIZE) + (DSIZE-1)) / DSIZE);
}
// search the free list for a fit
if((bp = find_fit(asize))!=NULL)
{
place(bp, asize);
return bp;
}
// no fit found, get more memory and place the block.
extendsize = MAX(asize, CHUNKSIZE);
if((bp = extend_heap(extendsize/WSIZE)) == NULL)
{
return NULL;
}
place(bp, asize);
return bp;
}
main.c
#include "heap.h"
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void *bp;
mm_init();
while(1)
{
bp = mm_malloc(400);
fprintf(stderr, "alloc %p.\n", bp);
mm_free(bp);
}
return 0;
}
运行过程:
多线程:
#include "heap.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static pthread_mutex_t mutex;
static void *write_msg_server(void *param)
{
void *bp;
while(1)
{
pthread_mutex_lock(&mutex);
bp = mm_malloc(400);
printf("%s line %d, bp=%p.\n", __func__, __LINE__, bp);
mm_free(bp);
pthread_mutex_unlock(&mutex);
}
return 0;
}
static void *read_msg_server(void *param)
{
void *bp;
while(1)
{
pthread_mutex_lock(&mutex);
bp = mm_malloc(400);
printf("%s line %d, bp=%p.\n", __func__, __LINE__, bp);
mm_free(bp);
pthread_mutex_unlock(&mutex);
}
return 0;
}
int main(void)
{
int ret;
void *bp;
mm_init();
pthread_t pthread_read;
pthread_t pthread_write;
pthread_mutex_init(&mutex, NULL);
int err = pthread_create(&pthread_read, NULL, read_msg_server, NULL);
if(err != 0)
{
perror("create pthread failure.");
return -1;
}
err = pthread_create(&pthread_write, NULL, write_msg_server, NULL);
if(err != 0)
{
perror("create pthread failure.");
return -1;
}
pthread_join(pthread_write, NULL);
pthread_join(pthread_read, NULL);
return 0;
}