faster malloc anyone?

Gregory Smith greg at utcsri.UUCP
Mon May 5 04:19:43 AEST 1986


In article <433 at geowhiz.UUCP> larry at geowhiz.UUCP (Larry McVoy) writes:
>each call to strsav().  So, I wrote the following little chunks of code and
>am requesting comments.  Can anyone point out why these are a *bad* idea 
>(aside from the obvious upper bound problem)?  Another problem is that
>free() won't work on these blocks...
	stay tuned...
>
>new.h:
># define	BLKSIZ		8096
>char* new();
>
>utils.c:
>/* utils.c -- strsav(), new() */
># include	"new.h"
>
>    char*
>strsav(s)
>    register char* s;
>{
>    char* strcpy();
>    register char* t;
>
>    t = new(strlen(s) + 1);	/* strings smaller than BLKSIZ */
>    return strcpy(t, s);
>}
>
>
>/*------------------------------------------------------------------02/May/86-*
> * new(size) - fast(??) memory allocator
> *
> * Inputs    -> (int)
> *
> * Returns   -> (char*)
> *
> * Results  ->The memory is allocated in big contiguous blocks via calloc(3).
> *		If the requst can fit in what's left of a block, then a block
> *		of the size requested is returned.  Otherwise, the rest of the
> *		block is discarded & a new block is allocated. 
> * 
> * Warning   -> This would seem to work great for little stuff.  Don't use it
> *		for big blocks.  Absolute largest allocatable block is BLKSIZ.
> *		For speed NO CHECK IS PERFORMED TO SEE IF THE REQUEST IS LESS
> *		THAN BLKSIZ.  BLKSIZ is guaranteed to be 1k or bigger (usually
> *		much bigger).
> * Revisions:
> *-----------------------------------------------------------------larry-*/
>    char*
>new(size)
>    register unsigned size;
>{
>    register char* blk;
>    static char* block = NULL;
>    static unsigned bytes_left = 0;
>
>    if (bytes_left < size)
			/* bytes_left should be set to BLKSIZ here */
>	if (!(block = calloc(1, BLKSIZ)))
>	    syserr("calloc in new");
>
>    blk = block;
>    block += size;
>    bytes -= size;
     return blk;		:-)
>}
>-- 

If the storage occupied by these strings can be released all at once,
the following 'new' can be used:


struct str_block{
	struct str_block *sb_link;
	char sb_chars[ BLKSIZ ];
} *allocated = NULL;
unsigned bytes_left = 0;
char* block;

char *new(size)
register unsigned size;
{   register char* blk;
    register struct str_block *new_blk;

    if (bytes_left < size){
	if ((new_blk =(struct str_block*) malloc(sizeof( struct str_block)))
		== NULL)
	    syserr("malloc in new");
	bytes_left = BLKSIZ;
	new_blk->sb_link = allocated;
	allocated = new_blk;
	block = new_blk->sb_chars;
    }
    blk = block;
    block += size;
    bytes_left -= size;
    return blk;
}

/*
 * this subroutine frees up all allocated memory
 */
forget(){
	register struct str_block *p;
	while( (p = allocated) != NULL ){
		allocated = p->sb_link;
		free(p);
	}
	bytes_left = 0;
}

I used a similar approach on a program I wrote recently - many small structs
needed to be allocated and reused during a certain phase of execution, and
then they were all released at once. So I got them from malloc in blocks of
about 200, and handled them on linked lists. When I was done, I released all
the blocks, which were kept on another linked list.

An enhancement: maintain separate 'allocated, bytes_left, block'
triplets for independent storage categories - then each category can be
'forgotten' independently of the others.

-- 
"For every action there is an equal and opposite malfunction"
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg



More information about the Comp.lang.c mailing list