[net.unix-wizards] compaction using realloc

dan@BBN-UNIX (12/10/82)

From: Dan Franklin <dan at BBN-UNIX>
Date:  6 Dec 1982 16:56:22 EST (Monday)
I agree; that code is highly implementation-dependent.  It knows that the last
storage freed is always the first storage allocated (if it fits).  This wouldn't
be so bad if that particular strategy weren't so awful in the general case.  I
once wrote a program which used stdio to read a lot of files (never more than
three were open simultaneously) and also permanently allocated a series of small
chunks of space (for a linked list).  It turns out that if you have a series of
such small allocations, interspersed with the malloc(512), free() statements
from stdio, that every 512-byte freed area gets at least one tiny chunk removed
from it, so EVERY TIME stdio reaches out for another buffer it causes an sbrk!
Essentially the program acted as though the free() simply weren't there!

It would be nice if we could fix malloc, and at the same time provide the
malloc_compact routine you suggest.  It would mean breaking those programs--like
the one that fragment of code came from--that relied on its LIFO behavior, but
the statement in the manual is so opaque that there probably aren't very many
such programs--and I for one would never rely on being able to get back freed
data (which I think the manual is recommending) in any case!

    Dan

thomas (12/13/82)

I have a version of malloc (which I got from somebody else) which we
are using on our Vaxen now.  It satisfies all memory requests by
allocating a block which is the next power of 2 bigger than the request.
This allows it to keep separate free lists for each size of request,
making malloc() much faster on a paging machine (it only needs to keep
29 free lists, most of which are never used).  Obviously it depends
on the fact that memory is cheap on a Vax.  We have a program which used
to go into horrendous thrashing as soon as its data space size reached
the amount of real memory on the system, do to the standard malloc's
behaviour of searching all blocks to find a free one.  Our malloc also
has a little instrumentation built into it, so you can easily find
"hardening of the arteries" if you are interested.  I have permission
from the author to distribute it, if anybody is interested, drop
me a line.

=Spencer (harpo!utah-cs!thomas, thomas@utah-20)

sch@MITRE-BEDFORD (12/15/82)

Date: Fri Dec 10 08:41:50 1982
The strategy used by malloc/free/realloc is a first fit method.  You are
suggesting using a best fit instead.  I believe if you do a study of the
literature (Knuth), you will find that there is a trade off here.  If you
use best fit (as you suggested) then the routine has to search all possible
blocks (slower), and many small chunks get allocated and never can be reused.

The whole allocation strategy of malloc does break down for large programs
on virtual memory systems like a vax.  Berkeley knows know about this I don't
no what their future solutions will be.

I agree with your general comment that one should not depend on the behaviour
of malloc returning the previously freed block.   Rather than changing
malloc/free, a new set of subroutines which do allocation but also garbage
collection would be handy.  These routines would have to return a pointer
to a pointer (char **) so the routine could move blocks around for garbage
collection.  Has anyone implemented such routines?

			Stephen Hemminger
			sch @ mitre-bedford

dan@BBN-UNIX (12/18/82)

From: Dan Franklin <dan at BBN-UNIX>
Date: 16 Dec 1982  0:55:40 EST (Thursday)
The algorithm used by malloc is a modified first fit (one that is probably not
in the literature); the "classical" first fit, such as that in the kernel
malloc, always starts searching from the beginning of the list.  I certainly
don't think best fit would be better;  I am sorry if my remarks seemed to imply
that.  At the time I wrote the letter, I thought that changing to "classical"
first fit--that is, always starting the search at the beginning of the
list--would be good, since it would at least avoid anomalous behavior,
even if it did make malloc more expensive (after a while, as Knuth points out,
you get a bunch of relatively small free areas at the beginning of the list that
you have to keep passing over).  A better idea (Knuth V1, answer to exercise 6
in section 2.5) is to start each search after the last block allocated;
randomizing the starting point randomizes the arrangement of free blocks,
leading to lower average search time to satisfy a malloc request.  The problem I
had would not have happened with this algorithm.

laman (12/22/82)

You say that you feel that the modified first fit is a better idea.  Why?
You will have a variable pointer of where to start searching through your list,
but you may start chopping up all your free blocks quicker since, if you are
asked for some blocks say ~1/2 free block size, they will be allocated from the
other blocks.  After a while you had better hope you don't get some requests
for some larger sized blocks after you have chopped up your free list blocks.
At least the "classical" first fit is a little better suited to this.
What this gets down to is that one must experiment some to find the method
that best suits one's needs.

It may be best if we save the net and battle this out between ourselves.

					Mike Laman
					...!sdcsvax!laman

gwyn@Brl (12/28/82)

From:     Doug Gwyn <gwyn@Brl>
Date:     18 Dec 82 17:00:58-EST (Sat)
Some years ago I implemented the first-fit allocation method using a
"roving" search-start pointer as you mentioned, along with combining
adjacent freed regions (identifiable because of "boundary tags")
during allocation searching.  The application was display processor
real-time segment management, and it worked well.  One drawback to
the "boundary-tag" approach is that it assumes there is no memory
in the pool other than that allocated through this package.  This is
NOT the case with the "malloc" scheme, whereby a user can increase
the program break directly without breaking malloc's operation.  I
have tried to think of ways of permitting fake "busy block" boundary
tags for uncontrolled heap space, but I couldn't think of anything
reasonable to do about it.  So malloc is still a sensible choice.