📄 alloc.c
字号:
/* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * 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. * * Permission is hereby granted to use or copy this program * for any purpose, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * */# include "private/gc_priv.h"# include <stdio.h># if !defined(MACOS) && !defined(MSWINCE)# include <signal.h># include <sys/types.h># endif/* * Separate free lists are maintained for different sized objects * up to MAXOBJSZ. * The call GC_allocobj(i,k) ensures that the freelist for * kind k objects of size i points to a non-empty * free list. It returns a pointer to the first entry on the free list. * In a single-threaded world, GC_allocobj may be called to allocate * an object of (small) size i as follows: * * opp = &(GC_objfreelist[i]); * if (*opp == 0) GC_allocobj(i, NORMAL); * ptr = *opp; * *opp = obj_link(ptr); * * Note that this is very fast if the free list is non-empty; it should * only involve the execution of 4 or 5 simple instructions. * All composite objects on freelists are cleared, except for * their first word. *//* * The allocator uses GC_allochblk to allocate large chunks of objects. * These chunks all start on addresses which are multiples of * HBLKSZ. Each allocated chunk has an associated header, * which can be located quickly based on the address of the chunk. * (See headers.c for details.) * This makes it possible to check quickly whether an * arbitrary address corresponds to an object administered by the * allocator. */word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */word GC_gc_no = 0;#ifndef SMALL_CONFIG int GC_incremental = 0; /* By default, stop the world. */#endifint GC_parallel = FALSE; /* By default, parallel GC is off. */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. */#ifdef THREADS GC_bool GC_world_stopped = FALSE;# define IF_THREADS(x) x#else# define IF_THREADS(x)#endifword 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-1998 by Silicon Graphics. All rights reserved. ","Copyright (c) 1999-2001 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.","See source code for details." };# include "version.h"#if defined(SAVE_CALL_CHAIN) && \ !(defined(REDIRECT_MALLOC) && defined(GC_HAVE_BUILTIN_BACKTRACE))# define SAVE_CALL_CHAIN_IN_GC /* This is only safe if the call chain save mechanism won't end up */ /* calling GC_malloc. The GNU C library documentation suggests */ /* that backtrace doesn't use malloc, but at least the initial */ /* call in some versions does seem to invoke the dynamic linker, */ /* which uses malloc. */#endif/* some more variables */extern signed_word GC_mem_found; /* Number of reclaimed longwords */ /* after garbage collection */GC_bool GC_dont_expand = 0;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); }unsigned long GC_time_limit = TIME_LIMIT;CLOCK_TYPE GC_start_time; /* Time at which we stopped world. */ /* used only in GC_timeout_stop_func. */int GC_n_attempts = 0; /* Number of attempts at finishing */ /* collection within GC_time_limit. */#if defined(SMALL_CONFIG) || defined(NO_CLOCK)# 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; if ((count++ & 3) != 0) return(0); GET_TIME(current_time); time_diff = MS_TIME_DIFF(current_time,GC_start_time); if (time_diff >= GC_time_limit) {# ifdef CONDPRINT if (GC_print_stats) { GC_printf0("Abandoning stopped marking after "); GC_printf1("%lu msecs", (unsigned long)time_diff); GC_printf1("(attempt %ld)\n", (unsigned long) GC_n_attempts); }# endif return(1); } return(0); }#endif /* !SMALL_CONFIG *//* Return the minimum number of words that must be allocated between *//* collections to amortize the collection cost. */static word min_words_allocd(){# ifdef THREADS /* We punt, for now. */ register signed_word stack_size = 10000;# else int dummy; register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;# endif 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 (TRUE_INCREMENTAL) { return scan_size / (2 * GC_free_space_divisor); } else { return scan_size / GC_free_space_divisor; }}/* Return the number of words allocated, adjusted for explicit storage *//* management, etc.. This number is used in deciding when to trigger *//* collections. */word GC_adj_words_allocd(){ register signed_word result; register signed_word expl_managed = BYTES_TO_WORDS((long)GC_non_gc_bytes - (long)GC_non_gc_bytes_at_gc); /* Don't count what was explicitly freed, or newly allocated for */ /* explicit management. Note that deallocating an explicitly */ /* managed object should not alter result, assuming the client */ /* is playing by the rules. */ result = (signed_word)GC_words_allocd - (signed_word)GC_mem_freed + (signed_word)GC_finalizer_mem_freed - expl_managed; if (result > (signed_word)GC_words_allocd) { result = GC_words_allocd; /* probably client bug or unfortunate scheduling */ } result += GC_words_finalized; /* We count objects enqueued for finalization as though they */ /* had been reallocated this round. Finalization is user */ /* visible progress. And if we don't count this, we have */ /* stability problems for programs that finalize all objects. */ if ((GC_words_wasted >> 3) < result) result += GC_words_wasted; /* This doesn't reflect useful work. But if there is lots of */ /* new fragmentation, the same is probably true of the heap, */ /* and the collection will be correspondingly cheaper. */ if (result < (signed_word)(GC_words_allocd >> 3)) { /* Always count at least 1/8 of the allocations. We don't want */ /* to collect too infrequently, since that would inhibit */ /* coalescing of free storage blocks. */ /* This also makes us partially robust against client bugs. */ return(GC_words_allocd >> 3); } else { return(result); }}/* Clear up a few frames worth of garbage left at the top of the stack. *//* This is used to prevent us from accidentally treating garbade left *//* on the stack by other parts of the collector as roots. This *//* differs from the code in misc.c, which actually tries to keep the *//* stack clear of long-lived, client-generated garbage. */void GC_clear_a_few_frames(){# define NWORDS 64 word frames[NWORDS]; /* Some compilers will warn that frames was set but never used. */ /* That's the whole idea ... */ register int i; for (i = 0; i < NWORDS; i++) frames[i] = 0;}/* Heap size at which we need a collection to avoid expanding past *//* limits used by blacklisting. */static word GC_collect_at_heapsize = (word)(-1);/* Have we allocated enough to amortize a collection? */GC_bool GC_should_collect(){ return(GC_adj_words_allocd() >= min_words_allocd() || GC_heapsize >= GC_collect_at_heapsize);}void GC_notify_full_gc(){ if (GC_start_call_back != (void (*) GC_PROTO((void)))0) { (*GC_start_call_back)(); }}GC_bool GC_is_full_gc = FALSE;/* * Initiate a garbage collection if appropriate. * Choose judiciously * between partial, full, and stop-world collections. * Assumes lock held, signals disabled. */void GC_maybe_gc(){ static int n_partial_gcs = 0; if (GC_should_collect()) { if (!GC_incremental) { GC_gcollect_inner(); n_partial_gcs = 0; return; } else {# ifdef PARALLEL_MARK GC_wait_for_reclaim();# endif if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) {# ifdef CONDPRINT if (GC_print_stats) { GC_printf2( "***>Full mark for collection %lu after %ld allocd bytes\n", (unsigned long) GC_gc_no+1, (long)WORDS_TO_BYTES(GC_words_allocd)); }# endif GC_promote_black_lists(); (void)GC_reclaim_all((GC_stop_func)0, TRUE); GC_clear_marks(); n_partial_gcs = 0; GC_notify_full_gc(); GC_is_full_gc = TRUE; } else { n_partial_gcs++; } } /* We try to mark with the world stopped. */ /* If we run out of time, this turns into */ /* incremental marking. */# ifndef NO_CLOCK if (GC_time_limit != GC_TIME_UNLIMITED) { GET_TIME(GC_start_time); }# endif if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED? GC_never_stop_func : GC_timeout_stop_func)) {# ifdef SAVE_CALL_CHAIN_IN_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++; } } }}/* * Stop the world garbage collection. Assumes lock held, signals disabled. * If stop_func is not GC_never_stop_func, then abort if stop_func returns TRUE. * Return TRUE if we successfully completed the collection. */GC_bool GC_try_to_collect_inner(stop_func)GC_stop_func stop_func;{# ifdef CONDPRINT CLOCK_TYPE start_time, current_time;# endif if (GC_dont_gc) return FALSE; if (GC_incremental && GC_collection_in_progress()) {# ifdef CONDPRINT if (GC_print_stats) { GC_printf0( "GC_try_to_collect_inner: finishing collection in progress\n"); }# endif /* CONDPRINT */ /* Just finish collection already in progress. */ while(GC_collection_in_progress()) { if (stop_func()) return(FALSE); GC_collect_a_little_inner(1); } } if (stop_func == GC_never_stop_func) GC_notify_full_gc();# ifdef CONDPRINT if (GC_print_stats) { if (GC_print_stats) GET_TIME(start_time); GC_printf2( "Initiating full world-stop collection %lu after %ld allocd bytes\n", (unsigned long) GC_gc_no+1, (long)WORDS_TO_BYTES(GC_words_allocd)); }# endif GC_promote_black_lists(); /* Make sure all blocks have been reclaimed, so sweep routines */ /* don't see cleared mark bits. */ /* If we're guaranteed to finish, then this is unnecessary. */ /* In the find_leak case, we have to finish to guarantee that */ /* previously unmarked objects are not reported as leaks. */# ifdef PARALLEL_MARK GC_wait_for_reclaim();# endif if ((GC_find_leak || stop_func != GC_never_stop_func)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -