summaryrefslogtreecommitdiffstats
path: root/boehm-gc/alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'boehm-gc/alloc.c')
-rw-r--r--boehm-gc/alloc.c212
1 files changed, 134 insertions, 78 deletions
diff --git a/boehm-gc/alloc.c b/boehm-gc/alloc.c
index c9d145e0369..3d0ddf05b36 100644
--- a/boehm-gc/alloc.c
+++ b/boehm-gc/alloc.c
@@ -1,6 +1,8 @@
/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
- * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1998 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -12,7 +14,6 @@
* modified is included with the above copyright notice.
*
*/
-/* Boehm, February 16, 1996 2:26 pm PST */
# include "gc_priv.h"
@@ -58,15 +59,25 @@ word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */
word GC_gc_no = 0;
-int GC_incremental = 0; /* By default, stop the world. */
+#ifndef SMALL_CONFIG
+ int GC_incremental = 0; /* By default, stop the world. */
+#endif
+
+int GC_full_freq = 19; /* Every 20th collection is a full */
+ /* collection, whether we need it */
+ /* or not. */
+
+GC_bool GC_need_full_gc = FALSE;
+ /* Need full GC do to heap growth. */
-int GC_full_freq = 4; /* Every 5th collection is a full */
- /* collection. */
+#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes)
+
+word GC_used_heap_size_after_full = 0;
char * GC_copyright[] =
{"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ",
"Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. ",
-"Copyright (c) 1996-1997 by Silicon Graphics. All rights reserved. ",
+"Copyright (c) 1996-1998 by Silicon Graphics. All rights reserved. ",
"THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
" EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.",
"See source code for details." };
@@ -80,16 +91,24 @@ extern signed_word GC_mem_found; /* Number of reclaimed longwords */
GC_bool GC_dont_expand = 0;
-word GC_free_space_divisor = 4;
+word GC_free_space_divisor = 3;
extern GC_bool GC_collection_in_progress();
+ /* Collection is in progress, or was abandoned. */
int GC_never_stop_func GC_PROTO((void)) { return(0); }
-CLOCK_TYPE GC_start_time;
+CLOCK_TYPE GC_start_time; /* Time at which we stopped world. */
+ /* used only in GC_timeout_stop_func. */
-int GC_timeout_stop_func GC_PROTO((void))
-{
+int GC_n_attempts = 0; /* Number of attempts at finishing */
+ /* collection within TIME_LIMIT */
+
+#ifdef SMALL_CONFIG
+# define GC_timeout_stop_func GC_never_stop_func
+#else
+ int GC_timeout_stop_func GC_PROTO((void))
+ {
CLOCK_TYPE current_time;
static unsigned count = 0;
unsigned long time_diff;
@@ -101,13 +120,15 @@ int GC_timeout_stop_func GC_PROTO((void))
if (time_diff >= TIME_LIMIT) {
# ifdef PRINTSTATS
GC_printf0("Abandoning stopped marking after ");
- GC_printf1("%lu msecs\n", (unsigned long)time_diff);
+ GC_printf1("%lu msecs", (unsigned long)time_diff);
+ GC_printf1("(attempt %d)\n", (unsigned long) GC_n_attempts);
# endif
return(1);
}
#endif
return(0);
-}
+ }
+#endif /* !SMALL_CONFIG */
/* Return the minimum number of words that must be allocated between */
/* collections to amortize the collection cost. */
@@ -120,18 +141,22 @@ static word min_words_allocd()
int dummy;
register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;
# endif
- register word total_root_size; /* includes double stack size, */
+ word total_root_size; /* includes double stack size, */
/* since the stack is expensive */
/* to scan. */
+ word scan_size; /* Estimate of memory to be scanned */
+ /* during normal GC. */
if (stack_size < 0) stack_size = -stack_size;
total_root_size = 2 * stack_size + GC_root_size;
+ scan_size = BYTES_TO_WORDS(GC_heapsize - GC_large_free_bytes
+ + (GC_large_free_bytes >> 2)
+ /* use a bit more of large empty heap */
+ + total_root_size);
if (GC_incremental) {
- return(BYTES_TO_WORDS(GC_heapsize + total_root_size)
- / (2 * GC_free_space_divisor));
+ return scan_size / (2 * GC_free_space_divisor);
} else {
- return(BYTES_TO_WORDS(GC_heapsize + total_root_size)
- / GC_free_space_divisor);
+ return scan_size / GC_free_space_divisor;
}
}
@@ -196,6 +221,7 @@ GC_bool GC_should_collect()
return(GC_adj_words_allocd() >= min_words_allocd());
}
+
void GC_notify_full_gc()
{
if (GC_start_call_back != (void (*)())0) {
@@ -203,6 +229,8 @@ void GC_notify_full_gc()
}
}
+GC_bool GC_is_full_gc = FALSE;
+
/*
* Initiate a garbage collection if appropriate.
* Choose judiciously
@@ -212,13 +240,14 @@ void GC_notify_full_gc()
void GC_maybe_gc()
{
static int n_partial_gcs = 0;
+
if (GC_should_collect()) {
if (!GC_incremental) {
GC_notify_full_gc();
GC_gcollect_inner();
n_partial_gcs = 0;
return;
- } else if (n_partial_gcs >= GC_full_freq) {
+ } else if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) {
# ifdef PRINTSTATS
GC_printf2(
"***>Full mark for collection %lu after %ld allocd bytes\n",
@@ -230,6 +259,7 @@ void GC_maybe_gc()
GC_clear_marks();
n_partial_gcs = 0;
GC_notify_full_gc();
+ GC_is_full_gc = TRUE;
} else {
n_partial_gcs++;
}
@@ -244,7 +274,12 @@ void GC_maybe_gc()
GC_save_callers(GC_last_stack);
# endif
GC_finish_collection();
- }
+ } else {
+ if (!GC_is_full_gc) {
+ /* Count this as the first attempt */
+ GC_n_attempts++;
+ }
+ }
}
}
@@ -256,7 +291,7 @@ void GC_maybe_gc()
GC_bool GC_try_to_collect_inner(stop_func)
GC_stop_func stop_func;
{
- if (GC_collection_in_progress()) {
+ if (GC_incremental && GC_collection_in_progress()) {
# ifdef PRINTSTATS
GC_printf0(
"GC_try_to_collect_inner: finishing collection in progress\n");
@@ -287,6 +322,7 @@ GC_stop_func stop_func;
# ifdef SAVE_CALL_CHAIN
GC_save_callers(GC_last_stack);
# endif
+ GC_is_full_gc = TRUE;
if (!GC_stopped_mark(stop_func)) {
if (!GC_incremental) {
/* We're partially done and have no way to complete or use */
@@ -306,32 +342,48 @@ GC_stop_func stop_func;
/*
* Perform n units of garbage collection work. A unit is intended to touch
- * roughly a GC_RATE pages. Every once in a while, we do more than that.
+ * roughly GC_RATE pages. Every once in a while, we do more than that.
+ * This needa to be a fairly large number with our current incremental
+ * GC strategy, since otherwise we allocate too much during GC, and the
+ * cleanup gets expensive.
*/
-# define GC_RATE 8
+# define GC_RATE 10
+# define MAX_PRIOR_ATTEMPTS 1
+ /* Maximum number of prior attempts at world stop marking */
+ /* A value of 1 means that we finish the seconf time, no matter */
+ /* how long it takes. Doesn't count the initial root scan */
+ /* for a full GC. */
int GC_deficit = 0; /* The number of extra calls to GC_mark_some */
/* that we have made. */
- /* Negative values are equivalent to 0. */
void GC_collect_a_little_inner(n)
int n;
{
register int i;
- if (GC_collection_in_progress()) {
+ if (GC_incremental && GC_collection_in_progress()) {
for (i = GC_deficit; i < GC_RATE*n; i++) {
- if (GC_mark_some()) {
+ if (GC_mark_some((ptr_t)0)) {
/* Need to finish a collection */
# ifdef SAVE_CALL_CHAIN
GC_save_callers(GC_last_stack);
# endif
- (void) GC_stopped_mark(GC_never_stop_func);
+ if (GC_n_attempts < MAX_PRIOR_ATTEMPTS) {
+ GET_TIME(GC_start_time);
+ if (!GC_stopped_mark(GC_timeout_stop_func)) {
+ GC_n_attempts++;
+ break;
+ }
+ } else {
+ (void)GC_stopped_mark(GC_never_stop_func);
+ }
GC_finish_collection();
break;
}
}
if (GC_deficit > 0) GC_deficit -= GC_RATE*n;
+ if (GC_deficit < 0) GC_deficit = 0;
} else {
GC_maybe_gc();
}
@@ -354,15 +406,14 @@ int GC_collect_a_little GC_PROTO(())
/*
* Assumes lock is held, signals are disabled.
* We stop the world.
- * If final is TRUE, then we finish the collection, no matter how long
- * it takes.
- * Otherwise we may fail and return FALSE if this takes too long.
+ * If stop_func() ever returns TRUE, we may fail and return FALSE.
* Increment GC_gc_no if we succeed.
*/
GC_bool GC_stopped_mark(stop_func)
GC_stop_func stop_func;
{
register int i;
+ int dummy;
# ifdef PRINTSTATS
CLOCK_TYPE start_time, current_time;
# endif
@@ -393,7 +444,7 @@ GC_stop_func stop_func;
START_WORLD();
return(FALSE);
}
- if (GC_mark_some()) break;
+ if (GC_mark_some((ptr_t)(&dummy))) break;
}
GC_gc_no++;
@@ -439,7 +490,7 @@ void GC_finish_collection()
# ifdef GATHERSTATS
GC_mem_found = 0;
# endif
-# ifdef FIND_LEAK
+ if (GC_find_leak) {
/* Mark all objects on the free list. All objects should be */
/* marked when we're done. */
{
@@ -462,25 +513,26 @@ void GC_finish_collection()
}
}
}
- /* Check that everything is marked */
GC_start_reclaim(TRUE);
-# else
+ /* The above just checks; it doesn't really reclaim anything. */
+ }
+
+ GC_finalize();
+# ifdef STUBBORN_ALLOC
+ GC_clean_changing_list();
+# endif
- GC_finalize();
-# ifdef STUBBORN_ALLOC
- GC_clean_changing_list();
-# endif
-
-# ifdef PRINTTIMES
- GET_TIME(finalize_time);
-# endif
-
- /* Clear free list mark bits, in case they got accidentally marked */
- /* Note: HBLKPTR(p) == pointer to head of block containing *p */
- /* Also subtract memory remaining from GC_mem_found count. */
- /* Note that composite objects on free list are cleared. */
- /* Thus accidentally marking a free list is not a problem; only */
- /* objects on the list itself will be marked, and that's fixed here. */
+# ifdef PRINTTIMES
+ GET_TIME(finalize_time);
+# endif
+
+ /* Clear free list mark bits, in case they got accidentally marked */
+ /* Note: HBLKPTR(p) == pointer to head of block containing *p */
+ /* (or GC_find_leak is set and they were intentionally marked.) */
+ /* Also subtract memory remaining from GC_mem_found count. */
+ /* Note that composite objects on free list are cleared. */
+ /* Thus accidentally marking a free list is not a problem; only */
+ /* objects on the list itself will be marked, and that's fixed here. */
{
register word size; /* current object size */
register ptr_t p; /* pointer to current object */
@@ -506,26 +558,37 @@ void GC_finish_collection()
}
-# ifdef PRINTSTATS
+# ifdef PRINTSTATS
GC_printf1("Bytes recovered before sweep - f.l. count = %ld\n",
(long)WORDS_TO_BYTES(GC_mem_found));
-# endif
-
+# endif
/* Reconstruct free lists to contain everything not marked */
- GC_start_reclaim(FALSE);
-
-# endif /* !FIND_LEAK */
+ GC_start_reclaim(FALSE);
+ if (GC_is_full_gc) {
+ GC_used_heap_size_after_full = USED_HEAP_SIZE;
+ GC_need_full_gc = FALSE;
+ } else {
+ GC_need_full_gc =
+ BYTES_TO_WORDS(USED_HEAP_SIZE - GC_used_heap_size_after_full)
+ > min_words_allocd();
+ }
# ifdef PRINTSTATS
GC_printf2(
- "Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
+ "Immediately reclaimed %ld bytes in heap of size %lu bytes",
(long)WORDS_TO_BYTES(GC_mem_found),
(unsigned long)GC_heapsize);
- GC_printf2("%lu (atomic) + %lu (composite) collectable bytes in use\n",
- (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
- (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
+# ifdef USE_MUNMAP
+ GC_printf1("(%lu unmapped)", GC_unmapped_bytes);
+# endif
+ GC_printf2(
+ "\n%lu (atomic) + %lu (composite) collectable bytes in use\n",
+ (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
+ (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
# endif
+ GC_n_attempts = 0;
+ GC_is_full_gc = FALSE;
/* Reset or increment counters for next cycle */
GC_words_allocd_before_gc += GC_words_allocd;
GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
@@ -533,6 +596,9 @@ void GC_finish_collection()
GC_words_wasted = 0;
GC_mem_freed = 0;
+# ifdef USE_MUNMAP
+ GC_unmap_old();
+# endif
# ifdef PRINTTIMES
GET_TIME(done_time);
GC_printf2("Finalize + initiate sweep took %lu + %lu msecs\n",
@@ -576,7 +642,7 @@ void GC_gcollect GC_PROTO(())
word GC_n_heap_sects = 0; /* Number of sections currently in heap. */
/*
- * Use the chunk of memory starting at p of syze bytes as part of the heap.
+ * Use the chunk of memory starting at p of size bytes as part of the heap.
* Assumes p is HBLKSIZE aligned, and bytes is a multiple of HBLKSIZE.
*/
void GC_add_to_heap(p, bytes)
@@ -584,6 +650,7 @@ struct hblk *p;
word bytes;
{
word words;
+ hdr * phdr;
if (GC_n_heap_sects >= MAX_HEAP_SECTS) {
ABORT("Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS");
@@ -598,7 +665,10 @@ word bytes;
GC_heap_sects[GC_n_heap_sects].hs_bytes = bytes;
GC_n_heap_sects++;
words = BYTES_TO_WORDS(bytes - HDR_BYTES);
- HDR(p) -> hb_sz = words;
+ phdr = HDR(p);
+ phdr -> hb_sz = words;
+ phdr -> hb_map = (char *)1; /* A value != GC_invalid_map */
+ phdr -> hb_flags = 0;
GC_freehblk(p);
GC_heapsize += bytes;
if ((ptr_t)p <= GC_least_plausible_heap_addr
@@ -614,21 +684,6 @@ word bytes;
}
}
-#ifdef PRESERVE_LAST
-GC_bool GC_in_last_heap_sect(p)
-ptr_t p;
-{
- struct HeapSect * last_heap_sect = &(GC_heap_sects[GC_n_heap_sects-1]);
- ptr_t start = last_heap_sect -> hs_start;
- ptr_t end;
-
- if (p < start) return FALSE;
- end = start + last_heap_sect -> hs_bytes;
- if (p >= end) return FALSE;
- return TRUE;
-}
-#endif
-
# if !defined(NO_DEBUGGING)
void GC_print_heap_sects()
{
@@ -772,7 +827,6 @@ GC_bool GC_collect_or_expand(needed_blocks, ignore_off_page)
word needed_blocks;
GC_bool ignore_off_page;
{
-
if (!GC_incremental && !GC_dont_gc && GC_should_collect()) {
GC_notify_full_gc();
GC_gcollect_inner();
@@ -805,9 +859,11 @@ GC_bool ignore_off_page;
WARN("Out of Memory! Returning NIL!\n", 0);
return(FALSE);
}
- } else if (GC_fail_count) {
+ } else {
# ifdef PRINTSTATS
- GC_printf0("Memory available again ...\n");
+ if (GC_fail_count) {
+ GC_printf0("Memory available again ...\n");
+ }
# endif
}
}
OpenPOWER on IntegriCloud