⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 alloc.c

📁 早期freebsd实现
💻 C
字号:
/* * Copyright (c) 1994 David I. Bell * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. * * Description: *	This is a very fast storage allocator. It allocates blocks of a small *	number of different sizes, and keeps free lists of each size.  Blocks *	that don't exactly fit are passed up to the next larger size.  In this *	implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long. *	This is designed for use in a program that uses vast quantities of *	memory, but bombs when it runs out. * * Abnormal Conditions *	This is a public domain storage allocator. * * Modifications: *	Date		Programmer		Description of modification *	27-FEB-90	Landon Curt Noll	most systems can ignore alloc.c *	2-OCT-89	David I. Bell		Add free list. Sbrk now optional *	30-JUN-87	Peter Miller		Made it work on Slimos. *	21-FEB-82	Chris Kingsley		Initial Coding *			kingsley@cit-20		Caltech */#include <stdio.h>#include "alloc.h"#include "have_stdlib.h"#ifdef HAVE_STDLIB_H# include <stdlib.h>#endif#if 0#define DEBUG	1		/* defined if debugging code enabled */#define MSTATS	1		/* defined if memory statistics kept */#endif#define	NO_SBRK	1		/* defined if cannot use sbrk */#if defined(CALC_MALLOC)/* * Make these functions really accessible here. */#undef	malloc#undef	realloc#undef	free#ifdef DEBUG#define assert(x,v) if ((x)==0) assertfailed(v)#else#define assert(x,v)#endiftypedef unsigned char u_char;typedef unsigned short u_short;typedef unsigned int u_int;typedef char * caddr_t;#ifdef NO_SBRKextern char * malloc();extern char * realloc();#elseextern char * sbrk();#endif/* * The overhead on a block is at least 4 bytes.  When free, this space * contains a pointer to the next free block, and the bottom two bits must * be zero.  When in use, the first byte is set to MAGIC, and the second * byte is the size index.  The remaining bytes are for alignment. * If range checking (RCHECK) is enabled and the size of the block fits * in two bytes, then the top two bytes hold the size of the requested block * plus the range checking words, and the header word MINUS ONE. */union overhead{	union overhead * ov_next;	/* when free */	struct	{		u_char ovu_magic;	/* magic number */		u_char ovu_index;	/* bucket # */#define ov_magic ovu.ovu_magic#define ov_index ovu.ovu_index#ifdef RCHECK		u_short ovu_size;	/* actual block size */		u_int ovu_rmagic;	/* range magic number */#define ov_size ovu.ovu_size#define ov_rmagic ovu.ovu_rmagic#endif	} ovu;};#define QUANTUM_NBITS	4#define QUANTUM		(1<<QUANTUM_NBITS)#define MAGIC	0xff		/* magic # on accounting info */#define RMAGIC	0x55555555	/* magic # on range info */#ifdef RCHECK#define RSLOP	sizeof(u_int)#else#define RSLOP	0#endif/* * nextf[i] is the pointer to the next free block of size 2^(i+3).  The * smallest allocatable block is 8 bytes.  The overhead information * precedes the data area returned to the user. */#define NBUCKETS	32	/* we can't run out on a 32 bit machine! */static union overhead * nextf[NBUCKETS];static union overhead *watchloc = 0;	/* location to be watched */#ifdef MSTATS/* * nmalloc[i] is the difference between the number of mallocs and frees * for a given block size. */static u_int nmalloc[NBUCKETS];#endif/* * Watch some allocated memory to see if it gets blasted. */allocwatch(cp)	char *cp;{	if (cp == NULL) {		watchloc = NULL;		return;	}	watchloc = (union overhead *)cp - 1;	assert(watchloc->ov_magic == MAGIC, 10);}alloccheck(){	assert((watchloc == NULL) || (watchloc->ov_magic == MAGIC), 11);}/* * NAME *	morecore - get more memory * * SYNOPSIS *	void *	morecore(bucket) *	int bucket; * * DESCRIPTION *	Morecore is used to allocate more memory to the indicated bucket. * * RETURNS *	void */static voidmorecore(bucket)	register u_int	bucket;{	register union overhead * op;	register u_int	rnu;	/* 2^rnu bytes will be requested */	register u_int	nblks;	/* become nblks blocks of the desired size */	register u_int	siz;	assert(bucket >= QUANTUM_NBITS, 1);	assert(bucket < NBUCKETS, 2);	assert(!nextf[bucket], 3);#ifndef NO_SBRK	/*	 * Insure memory is allocated on a page boundary.	 * Should make getpageize() call?	 */#define PAGE_SIZE (1<<10)	siz = (u_int)sbrk(0);	if(siz & (PAGE_SIZE-1))		sbrk(PAGE_SIZE - (siz & (PAGE_SIZE-1)));#endif	/* take 2k unless the block is bigger than that */	rnu = (bucket <= 11) ? 11 : bucket;	assert(rnu >= bucket, 4);	nblks = 1L << (rnu - bucket); /* how many blocks to get */	siz = 1L << rnu;#ifndef NO_SBRK	op = (union overhead *)sbrk(siz);	/* no more room! */	if ((int)op == -1)		return;	/*	 * Round up to minimum allocation size boundary	 * and deduct from block count to reflect.	 */	if((int)op & (QUANTUM-1))	{		op = (union overhead *)(((int)op + QUANTUM) &~ (QUANTUM-1));		nblks--;	}#else	op = (union overhead *)malloc(siz);	/* no more room! */	if (!op)		return;#endif	/*	 * Add new memory allocated to the	 * free list for this hash bucket.	 */	nextf[bucket] = op;	siz = 1L << bucket;	while (--nblks)	{		op->ov_next = (union overhead *)((caddr_t)op + siz);		op = op->ov_next;	}}/* * NAME *	mem_alloc - memory allocator * * SYNOPSIS *	char * *	mem_alloc() * * DESCRIPTION *	Mem_alloc is used to allocate memory large enought to fit the requested *	size, and on a boundary suitable for placing any value. * * RETURNS *	char *, pointer to base of dynamic memory allocated * * CAVEAT *	Use mem_free() when you are finished with the space. */char *mem_alloc(nbytes)	register unsigned long int nbytes;{	register union overhead *p;	register int	bucket;	register unsigned long int shiftr;	if (nbytes > ((unsigned int) -1))		return NULL;	assert((watchloc == NULL) || (watchloc->ov_magic == MAGIC), 12);	/*	 * Convert amount of memory requested into	 * closest block size stored in hash buckets	 * which satisfies request.  Account for	 * space used per block for accounting.	 */	nbytes = (nbytes + sizeof (union overhead) + RSLOP + (QUANTUM-1)) &~ (QUANTUM-1);	shiftr = (nbytes - 1) >> QUANTUM_NBITS;	/* apart from this loop, this is O(1) */	bucket = QUANTUM_NBITS;	while(shiftr)	{		shiftr >>= 1;		bucket++;	}	/*	 * If nothing in hash bucket right now,	 * request more memory from the system.	 */	if (!nextf[bucket])		morecore(bucket);	if (!(p = nextf[bucket]))		return (char*)0;	/* remove from linked list */	nextf[bucket] = p->ov_next;	p->ov_magic = MAGIC;	p->ov_index = bucket;#ifdef MSTATS	nmalloc[bucket]++;#endif#ifdef RCHECK	/*	 * Record allocated size of block and	 * bound space with magic numbers	 */	if (nbytes <= (1L<<16))		p->ov_size = nbytes - 1;	p->ov_rmagic = RMAGIC;	*((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;#endif	return ((char *)(p + 1));}/* * NAME *	mem_free - free memory * * SYNOPSIS *	int *	mem_free(cp) *	char * cp; * * DESCRIPTION *	Mem_free is used to release space allocated by mem_alloc *	or mem_realloc. * * RETURNS *	int * * CAVEAT *	do not pass mem_free() an argument that was returned by mem_alloc() *	or mem_realloc(). */intmem_free(cp)	char *	cp;{	register u_int	bucket;	register union overhead *op;	assert((watchloc == NULL) || (watchloc->ov_magic == MAGIC), 13);	if (!cp)		return;	op = (union overhead *)cp - 1;	assert(op->ov_magic == MAGIC, 5);	/* make sure it was in use */	assert(op->ov_index < NBUCKETS, 6);	assert(op->ov_index >= QUANTUM_NBITS, 7);#ifdef RCHECK	assert(op->ov_index > 16 || op->ov_size == (1L<<op->ov_index)-1, 8);	assert(op->ov_rmagic == RMAGIC, 9);	assert(op->ov_index > 16 || *(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC, 10);#endif#ifndef DEBUG	if(op->ov_magic != MAGIC)		return;		/* sanity */#endif	bucket = op->ov_index;	op->ov_next = nextf[bucket];	nextf[bucket] = op;#ifdef MSTATS	nmalloc[bucket]--;#endif}/* * NAME *	findbucket - find a bucket * * SYNOPSIS *	int *	findbucket(freep, srchlen) *	union overhead * freep; *	int srchlen; * * DESCRIPTION *	Findbucket is used to find the bucket a free block is in. *	Search ``srchlen'' elements of each free list for a block whose *	header starts at ``freep''.  If srchlen is -1 search the whole list. * * RETURNS *	bucket number, or -1 if not found. */static intfindbucket(freep, srchlen)	union overhead *	freep;	int	srchlen;{	register union overhead *p;	register int	i, j;	for (i = 0; i < NBUCKETS; i++)	{		j = 0;		for (p = nextf[i]; p && j != srchlen; p = p->ov_next)		{			if (p == freep)				return i;			j++;		}	}	return -1;}/* * When a program attempts "storage compaction" as mentioned in the * old malloc man page, it realloc's an already freed block.  Usually * this is the last block it freed; occasionally it might be farther * back.  We have to search all the free lists for the block in order * to determine its bucket: first we make one pass thru the lists * checking only the first block in each; if that fails we search * ``realloc_srchlen'' blocks in each list for a match (the variable * is extern so the caller can modify it).  If that fails we just copy * however many bytes was given to realloc() and hope it's not huge. */static int realloc_srchlen = 4;	/* 4 should be plenty, -1 =>'s whole list *//* * NAME *	mem_realloc - change size * * SYNOPSIS *	char *	mem_realloc(cp, nbytes) *	char * cp; *	u_int nbytes; * * DESCRIPTION *	Mem_realloc is used to enlarge a chunk of memory *	returned by mem_alloc() or mem_realloc(). * * RETURNS *	char *, pointer to base of dynamic memory allocated * * CAVEAT *	Use mem_free() when you are finished with the space. */char *mem_realloc(cp, nbytes)	char *cp;	unsigned long	nbytes;{	register u_int	old_nbytes;	register union overhead *op;	char *	res;	register u_int	old_bucket;	short	was_alloced = 0;	if (nbytes > ((unsigned int) -1))		return NULL;	assert((watchloc == NULL) || (watchloc->ov_magic == MAGIC), 14);	if (!cp)		return mem_alloc(nbytes);	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));	if (op->ov_magic == MAGIC)	{		was_alloced++;		old_bucket = op->ov_index;	}	else	{		/*		 * Already free, doing "compaction".		 *		 * Search for the old block of memory on the		 * free list. First, check the most common		 * case (last element free'd), then (this failing)		 * the last ``realloc_srchlen'' items free'd.		 * If all lookups fail, then assume the size of		 * the memory block being realloc'd is the		 * smallest possible.		 */		if		(			(old_bucket = findbucket(op, 1)) == -1		&&			(old_bucket = findbucket(op, realloc_srchlen)) == -1		)			old_bucket = QUANTUM_NBITS;	}	old_nbytes = (1L << old_bucket) - sizeof(union overhead) - RSLOP;	/*	 * avoid the copy if same size block	 */	if	(		was_alloced	&&		nbytes <= old_nbytes	&&		nbytes > (old_nbytes >> 1) - sizeof(union overhead) - RSLOP	)		return cp;	/*	 * grab another chunk	 */	if(!(res = mem_alloc(nbytes)))		return (char*)0;	assert(cp != res, 11);	memcpy(res, cp, (nbytes < old_nbytes) ? nbytes : old_nbytes);	if(was_alloced)		mem_free(cp);	return res;}#else /*CALC_MALLOC*/#undef MSTATS#endif /*CALC_MALLOC*//* * Allocate a new item from the specified free list. * Returns NULL if no item can be allocated. */ALLOCITEM *allocitem(fp)	FREELIST *fp;		/* free list header */{	FREEITEM *ip;		/* allocated item */	if (fp->curfree > 0) {		fp->curfree--;		ip = fp->freelist;		fp->freelist = ip->next;		return (ALLOCITEM *) ip;	}	ip = (FREEITEM *) malloc(fp->itemsize);	if (ip == NULL)		return NULL;	return (ALLOCITEM *) ip;}/* * Free an item by placing it back on a free list. * If too many items are on the list, it is really freed. */voidfreeitem(fp, ip)	FREELIST *fp;		/* freelist header */	FREEITEM *ip;		/* item to be freed */{	if (ip == NULL)		return;	if (fp->curfree >= fp->maxfree) {		free((char *) ip);		return;	}	ip->next = fp->freelist;	fp->freelist = ip;	fp->curfree++;}/* * NAME *	mem_stats - print memory statistics * * SYNOPSIS *	void *	mem_stats(s) *	char * s; * * DESCRIPTION *	Mem_stats is used to print out statistics about current memory usage. *	``s'' is the title string * *	Prints two lines of numbers, one showing the length of the free list *	for each size category, the second showing the number of mallocs - *	frees for each size category. * * RETURNS *	void *//*ARGSUSED*/voidmem_stats(s)	char *	s;{#ifdef MSTATS	register int	i, j;	register union overhead *p;	int	totfree = 0;	int	totused = 0;	fprintf(stderr, "Memory allocation statistics %s\n", s);	fprintf(stderr, "%11s:%12s%12s%12s\n", "Bucket", "In Use", "Free", "Sum");	for (i = 0; i < NBUCKETS; i++)	{		for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)			;		if(!j && !nmalloc[i])			continue;		fprintf(stderr, "%11d:%12d%12d%12d\n", (1L<<i), nmalloc[i], j, j+nmalloc[i]);		totfree += j * (1L << i);		totused += nmalloc[i] * (1L << i);	}	fprintf(stderr, "%11s:%12d%12d%12d\n", "Totals", totused, totfree, totused+totfree);#else	fprintf(stderr, 	    "Memory allocation stats were not compiled into calc\n");#endif}#ifdef DEBUGvoidassertfailed(n){	printf("Assertion %d failed\n", n);	exit(1);}#endif/* END CODE */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -