Change phkmalloc so that the page directory is now floating and allocated

via mmap() up around the shared library area.  Previously the directory
was allocated from space from it's own memory pool.  Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.)  I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)

I've been running this in my libc for about a month...

Also, seperate MALLOC_STATS from EXTRA_SANITY..  I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-)  I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.

Reviewed by: phk
This commit is contained in:
peter 1995-12-11 14:28:12 +00:00
parent efe2884ad5
commit 2cd62d62e4

View File

@ -6,7 +6,7 @@
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* $Id: malloc.c,v 1.5 1995/10/08 18:44:20 phk Exp $
* $Id: malloc.c,v 1.6 1995/10/22 14:47:00 phk Exp $
*
*/
@ -16,6 +16,17 @@
*/
#undef EXTRA_SANITY
/*
* Defining MALLOC_STATS will enable you to call malloc_dump() and set
* the [dD] options in the MALLOC_OPTIONS environment variable.
* It has no run-time performance hit.
*/
#define MALLOC_STATS
#if defined(EXTRA_SANITY) && !defined(MALLOC_STATS)
# define MALLOC_STATS /* required for EXTRA_SANITY */
#endif
/*
* What to use for Junk
*/
@ -213,12 +224,12 @@ static int malloc_abort;
*/
static int suicide;
#ifdef EXTRA_SANITY
#ifdef MALLOC_STATS
/*
* dump statistics
*/
static int malloc_stats;
#endif /* EXTRA_SANITY */
#endif /* MALLOC_STATS */
/*
* always realloc ?
@ -250,7 +261,7 @@ static struct pgfree *px;
*/
static int extend_pgdir(u_long index);
#ifdef EXTRA_SANITY
#ifdef MALLOC_STATS
void
malloc_dump(FILE *fd)
{
@ -306,7 +317,7 @@ malloc_dump(FILE *fd)
(last_index + malloc_pageshift) << malloc_pageshift);
fprintf(fd,"Break\t%ld\n",(u_long)sbrk(0) >> malloc_pageshift);
}
#endif /* EXTRA_SANITY */
#endif /* MALLOC_STATS */
static void
wrterror(char *p)
@ -315,10 +326,10 @@ wrterror(char *p)
suicide = 1;
write(2,q,strlen(q));
write(2,p,strlen(p));
#ifdef EXTRA_SANITY
#ifdef MALLOC_STATS
if (malloc_stats)
malloc_dump(stderr);
#endif /* EXTRA_SANITY */
#endif /* MALLOC_STATS */
abort();
}
@ -428,20 +439,38 @@ static int
extend_pgdir(u_long index)
{
struct pginfo **new,**old;
int i;
int i, oldlen;
/* Make it this many pages */
i = index * sizeof *page_dir;
i /= malloc_pagesize;
i += 2;
/* remember the old mapping size */
oldlen = malloc_ninfo * sizeof *page_dir;
/*
* NOTE: we allocate new pages and copy the directory rather than tempt
* fate by trying to "grow" the region.. There is nothing to prevent
* us from accidently re-mapping space that's been allocated by our caller
* via dlopen() or other mmap().
*
* The copy problem is not too bad, as there is 4K of page index per
* 4MB of malloc arena.
*
* We can totally avoid the copy if we open a file descriptor to associate
* the anon mappings with. Then, when we remap the pages at the new
* address, the old pages will be "magically" remapped.. But this means
* keeping open a "secret" file descriptor.....
*/
/* Get new pages */
new = (struct pginfo**) map_pages(i,0);
if (!new)
new = (struct pginfo**) mmap(0, i * malloc_pagesize, PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE, -1, 0);
if (new == (struct pginfo **)-1)
return 0;
/* Copy the old stuff */
memset(new, 0, i * malloc_pagesize);
memcpy(new, page_dir,
malloc_ninfo * sizeof *page_dir);
@ -452,15 +481,8 @@ extend_pgdir(u_long index)
old = page_dir;
page_dir = new;
/* Mark the pages */
index = ptr2index(new);
page_dir[index] = MALLOC_FIRST;
while (--i) {
page_dir[++index] = MALLOC_FOLLOW;
}
/* Now free the old stuff */
free(old);
munmap((caddr_t)old, oldlen);
return 1;
}
@ -480,10 +502,10 @@ malloc_init ()
switch (*p) {
case 'a': malloc_abort = 0; break;
case 'A': malloc_abort = 1; break;
#ifdef EXTRA_SANITY
#ifdef MALLOC_STATS
case 'd': malloc_stats = 0; break;
case 'D': malloc_stats = 1; break;
#endif /* EXTRA_SANITY */
#endif /* MALLOC_STATS */
case 'r': malloc_realloc = 0; break;
case 'R': malloc_realloc = 1; break;
case 'j': malloc_junk = 0; break;
@ -557,24 +579,20 @@ malloc_init ()
#endif /* malloc_minsize */
/* Allocate one page for the page directory */
page_dir = (struct pginfo **) map_pages(1,0);
if (!page_dir)
page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE, -1, 0);
if (page_dir == (struct pginfo **) -1)
wrterror("(Init) my first mmap failed. (check limits ?)\n");
/*
* We need a maximum of malloc_pageshift buckets, steal these from the
* front of the page_directory;
*/
malloc_origo = (u_long) page_dir >> malloc_pageshift;
malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift;
malloc_origo -= malloc_pageshift;
memset(page_dir,0,malloc_pagesize);
malloc_ninfo = malloc_pagesize / sizeof *page_dir;
/* Plug the page directory into itself */
page_dir[ptr2index(page_dir)] = MALLOC_FIRST;
/* Been here, done that */
initialized++;
}