mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-30 00:40:20 +02:00
(SCM_MTRIGGER_HYSTERESIS): Removed.
(scm_i_minyield_malloc, check_mtrigger): New. (scm_must_malloc, scm_must_realloc, scm_done_malloc): Use it instead of explicit code. Thanks to Han-Wen Nienhuys!
This commit is contained in:
parent
f721dc1de1
commit
dea8a73c42
1 changed files with 91 additions and 101 deletions
192
libguile/gc.c
192
libguile/gc.c
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
|
/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2003 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -51,6 +51,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#ifdef __ia64__
|
#ifdef __ia64__
|
||||||
#include <ucontext.h>
|
#include <ucontext.h>
|
||||||
|
@ -240,12 +241,6 @@ SCM_DEFINE (scm_set_debug_cell_accesses_x, "set-debug-cell-accesses!", 1, 0, 0,
|
||||||
*
|
*
|
||||||
* INIT_MALLOC_LIMIT is the initial amount of malloc usage which will
|
* INIT_MALLOC_LIMIT is the initial amount of malloc usage which will
|
||||||
* trigger a GC.
|
* trigger a GC.
|
||||||
*
|
|
||||||
* SCM_MTRIGGER_HYSTERESIS is the amount of malloc storage that must be
|
|
||||||
* reclaimed by a GC triggered by must_malloc. If less than this is
|
|
||||||
* reclaimed, the trigger threshold is raised. [I don't know what a
|
|
||||||
* good value is. I arbitrarily chose 1/10 of the INIT_MALLOC_LIMIT to
|
|
||||||
* work around a oscillation that caused almost constant GC.]
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -282,10 +277,14 @@ size_t scm_default_max_segment_size = 2097000L;/* a little less (adm) than 2 Mb
|
||||||
# define SCM_HEAP_SEG_SIZE (16384L * sizeof (scm_t_cell))
|
# define SCM_HEAP_SEG_SIZE (16384L * sizeof (scm_t_cell))
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Make heap grow with factor 1.5 */
|
/* Make heap grow with factor 1.5 */
|
||||||
#define SCM_EXPHEAP(scm_heap_size) (scm_heap_size / 2)
|
#define SCM_EXPHEAP(scm_heap_size) (scm_heap_size / 2)
|
||||||
#define SCM_INIT_MALLOC_LIMIT 100000
|
|
||||||
#define SCM_MTRIGGER_HYSTERESIS (SCM_INIT_MALLOC_LIMIT/10)
|
/*
|
||||||
|
At startup GUILE takes about 100k bytes.
|
||||||
|
*/
|
||||||
|
#define SCM_INIT_MALLOC_LIMIT 200000
|
||||||
|
|
||||||
/* CELL_UP and CELL_DN are used by scm_init_heap_seg to find (scm_t_cell * span)
|
/* CELL_UP and CELL_DN are used by scm_init_heap_seg to find (scm_t_cell * span)
|
||||||
aligned inner bounds for allocated storage */
|
aligned inner bounds for allocated storage */
|
||||||
|
@ -314,7 +313,8 @@ size_t scm_default_max_segment_size = 2097000L;/* a little less (adm) than 2 Mb
|
||||||
/* scm_freelists
|
/* scm_freelists
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct scm_t_freelist {
|
typedef struct scm_t_freelist
|
||||||
|
{
|
||||||
/* collected cells */
|
/* collected cells */
|
||||||
SCM cells;
|
SCM cells;
|
||||||
/* number of cells left to collect before cluster is full */
|
/* number of cells left to collect before cluster is full */
|
||||||
|
@ -347,7 +347,8 @@ typedef struct scm_t_freelist {
|
||||||
* belonging to this list.
|
* belonging to this list.
|
||||||
*/
|
*/
|
||||||
unsigned long heap_size;
|
unsigned long heap_size;
|
||||||
} scm_t_freelist;
|
}
|
||||||
|
scm_t_freelist;
|
||||||
|
|
||||||
SCM scm_freelist = SCM_EOL;
|
SCM scm_freelist = SCM_EOL;
|
||||||
scm_t_freelist scm_master_freelist = {
|
scm_t_freelist scm_master_freelist = {
|
||||||
|
@ -1938,6 +1939,43 @@ scm_gc_sweep ()
|
||||||
* during garbage collection.
|
* during garbage collection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scm_i_minyield_malloc is the minimum expected amount of malloc
|
||||||
|
* storage freed during a GC triggered by scm_must_malloc, etc, in
|
||||||
|
* percent of the size of the malloc heap. When this yield is not
|
||||||
|
* reached, the malloc heap is allowed to grow larger before
|
||||||
|
* triggering the next GC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int scm_i_minyield_malloc = 40;
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_mtrigger (char const * what )
|
||||||
|
{
|
||||||
|
if (scm_mallocated > scm_mtrigger)
|
||||||
|
{
|
||||||
|
long prev_alloced = scm_mallocated;
|
||||||
|
float yield;
|
||||||
|
scm_igc (what);
|
||||||
|
yield = (prev_alloced - scm_mallocated) / (float) prev_alloced;
|
||||||
|
|
||||||
|
if (yield < scm_i_minyield_malloc / 100.0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If you have a program that builds up a lot of data in
|
||||||
|
strings, then the desired yield will never be satisfied.
|
||||||
|
So we make the trigger a little larger, even.
|
||||||
|
|
||||||
|
Instead of getting bogged down, we let the mtrigger grow
|
||||||
|
strongly with it.
|
||||||
|
|
||||||
|
*/
|
||||||
|
scm_mtrigger = (int)((scm_mallocated * 110.0)
|
||||||
|
/ (100 - scm_i_minyield_malloc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* scm_must_malloc
|
/* scm_must_malloc
|
||||||
* Return newly malloced storage or throw an error.
|
* Return newly malloced storage or throw an error.
|
||||||
*
|
*
|
||||||
|
@ -1949,65 +1987,43 @@ scm_gc_sweep ()
|
||||||
*
|
*
|
||||||
* The limit scm_mtrigger may be raised by this allocation.
|
* The limit scm_mtrigger may be raised by this allocation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void *
|
void *
|
||||||
scm_must_malloc (size_t size, const char *what)
|
scm_must_malloc (size_t size, const char *what)
|
||||||
{
|
{
|
||||||
void *ptr;
|
void *ptr;
|
||||||
unsigned long nm = scm_mallocated + size;
|
|
||||||
|
unsigned long nm;
|
||||||
if (nm < size)
|
|
||||||
/* The byte count of allocated objects has overflowed. This is
|
|
||||||
probably because you forgot to report the correct size of freed
|
|
||||||
memory in some of your smob free methods. */
|
|
||||||
abort ();
|
|
||||||
|
|
||||||
if (nm <= scm_mtrigger)
|
|
||||||
{
|
|
||||||
SCM_SYSCALL (ptr = malloc (size));
|
|
||||||
if (NULL != ptr)
|
|
||||||
{
|
|
||||||
scm_mallocated = nm;
|
|
||||||
#ifdef GUILE_DEBUG_MALLOC
|
|
||||||
scm_malloc_register (ptr, what);
|
|
||||||
#endif
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scm_igc (what);
|
|
||||||
|
|
||||||
nm = scm_mallocated + size;
|
|
||||||
|
|
||||||
if (nm < size)
|
|
||||||
/* The byte count of allocated objects has overflowed. This is
|
|
||||||
probably because you forgot to report the correct size of freed
|
|
||||||
memory in some of your smob free methods. */
|
|
||||||
abort ();
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
run a slight risk here, in the unlikely event that realloc would
|
||||||
|
return NULL, but wouldn't if we did the GC in check_mtrigger.
|
||||||
|
*/
|
||||||
|
|
||||||
|
scm_mallocated += size;
|
||||||
SCM_SYSCALL (ptr = malloc (size));
|
SCM_SYSCALL (ptr = malloc (size));
|
||||||
|
check_mtrigger (what);
|
||||||
|
|
||||||
|
nm = scm_mallocated;
|
||||||
|
if (nm < size)
|
||||||
|
/* The byte count of allocated objects has overflowed. This is
|
||||||
|
probably because you forgot to report the correct size of freed
|
||||||
|
memory in some of your smob free methods. */
|
||||||
|
abort ();
|
||||||
|
|
||||||
if (NULL != ptr)
|
if (NULL != ptr)
|
||||||
{
|
{
|
||||||
scm_mallocated = nm;
|
|
||||||
if (nm > scm_mtrigger - SCM_MTRIGGER_HYSTERESIS) {
|
|
||||||
if (nm > scm_mtrigger)
|
|
||||||
scm_mtrigger = nm + nm / 2;
|
|
||||||
else
|
|
||||||
scm_mtrigger += scm_mtrigger / 2;
|
|
||||||
}
|
|
||||||
#ifdef GUILE_DEBUG_MALLOC
|
#ifdef GUILE_DEBUG_MALLOC
|
||||||
scm_malloc_register (ptr, what);
|
scm_malloc_register (ptr, what);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
scm_memory_error (what);
|
scm_memory_error (what);
|
||||||
|
assert (0);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* scm_must_realloc
|
|
||||||
* is similar to scm_must_malloc.
|
|
||||||
*/
|
|
||||||
void *
|
void *
|
||||||
scm_must_realloc (void *where,
|
scm_must_realloc (void *where,
|
||||||
size_t old_size,
|
size_t old_size,
|
||||||
|
@ -2015,59 +2031,44 @@ scm_must_realloc (void *where,
|
||||||
const char *what)
|
const char *what)
|
||||||
{
|
{
|
||||||
void *ptr;
|
void *ptr;
|
||||||
unsigned long nm;
|
|
||||||
|
|
||||||
if (size <= old_size)
|
if (size <= old_size)
|
||||||
return where;
|
return where;
|
||||||
|
|
||||||
nm = scm_mallocated + size - old_size;
|
|
||||||
|
|
||||||
if (nm < (size - old_size))
|
/*
|
||||||
/* The byte count of allocated objects has overflowed. This is
|
run a slight risk here, in the unlikely event that realloc would
|
||||||
probably because you forgot to report the correct size of freed
|
return NULL, but wouldn't if we did the GC in check_mtrigger.
|
||||||
memory in some of your smob free methods. */
|
*/
|
||||||
abort ();
|
if (scm_mallocated < 0)
|
||||||
|
|
||||||
if (nm <= scm_mtrigger)
|
|
||||||
{
|
|
||||||
SCM_SYSCALL (ptr = realloc (where, size));
|
|
||||||
if (NULL != ptr)
|
|
||||||
{
|
|
||||||
scm_mallocated = nm;
|
|
||||||
#ifdef GUILE_DEBUG_MALLOC
|
|
||||||
scm_malloc_reregister (where, ptr, what);
|
|
||||||
#endif
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scm_igc (what);
|
|
||||||
|
|
||||||
nm = scm_mallocated + size - old_size;
|
|
||||||
|
|
||||||
if (nm < (size - old_size))
|
|
||||||
/* The byte count of allocated objects has overflowed. This is
|
/* The byte count of allocated objects has overflowed. This is
|
||||||
probably because you forgot to report the correct size of freed
|
probably because you forgot to report the correct size of freed
|
||||||
memory in some of your smob free methods. */
|
memory in some of your smob free methods. */
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
|
/*
|
||||||
|
We don't want to get 0 back if we try to alloc 0 bytes, because
|
||||||
|
scm_must_free() won't take NULL.
|
||||||
|
*/
|
||||||
|
scm_mallocated += size - old_size;
|
||||||
SCM_SYSCALL (ptr = realloc (where, size));
|
SCM_SYSCALL (ptr = realloc (where, size));
|
||||||
|
|
||||||
|
check_mtrigger (what);
|
||||||
|
|
||||||
if (NULL != ptr)
|
if (NULL != ptr)
|
||||||
{
|
{
|
||||||
scm_mallocated = nm;
|
|
||||||
if (nm > scm_mtrigger - SCM_MTRIGGER_HYSTERESIS) {
|
|
||||||
if (nm > scm_mtrigger)
|
|
||||||
scm_mtrigger = nm + nm / 2;
|
|
||||||
else
|
|
||||||
scm_mtrigger += scm_mtrigger / 2;
|
|
||||||
}
|
|
||||||
#ifdef GUILE_DEBUG_MALLOC
|
#ifdef GUILE_DEBUG_MALLOC
|
||||||
scm_malloc_reregister (where, ptr, what);
|
if(where)
|
||||||
|
scm_malloc_reregister (where, ptr, what);
|
||||||
|
else
|
||||||
|
scm_malloc_register (ptr, what);
|
||||||
#endif
|
#endif
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
scm_memory_error (what);
|
scm_memory_error (what);
|
||||||
|
assert(0);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
|
@ -2135,18 +2136,7 @@ scm_done_malloc (long size)
|
||||||
}
|
}
|
||||||
|
|
||||||
scm_mallocated += size;
|
scm_mallocated += size;
|
||||||
|
check_mtrigger ("foreign mallocs");
|
||||||
if (scm_mallocated > scm_mtrigger)
|
|
||||||
{
|
|
||||||
scm_igc ("foreign mallocs");
|
|
||||||
if (scm_mallocated > scm_mtrigger - SCM_MTRIGGER_HYSTERESIS)
|
|
||||||
{
|
|
||||||
if (scm_mallocated > scm_mtrigger)
|
|
||||||
scm_mtrigger = scm_mallocated + scm_mallocated / 2;
|
|
||||||
else
|
|
||||||
scm_mtrigger += scm_mtrigger / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue