📄 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-2004 Hewlett-Packard Development Company, L.P. * * 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 MAXOBJBYTES. * 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"/* some more variables */extern signed_word GC_bytes_found; /* Number of reclaimed bytes */ /* 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 (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 (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) { if (GC_print_stats) { GC_log_printf("Abandoning stopped marking after "); GC_log_printf("%lu msecs", time_diff); GC_log_printf("(attempt %d)\n", GC_n_attempts); } 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_bytes_allocd(){# ifdef THREADS /* We punt, for now. */ signed_word stack_size = 10000;# else int dummy; 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 = 2 * GC_composite_in_use + GC_atomic_in_use + 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 bytes allocated, adjusted for explicit storage *//* management, etc.. This number is used in deciding when to trigger *//* collections. */word GC_adj_bytes_allocd(void){ signed_word result; signed_word expl_managed = (signed_word)GC_non_gc_bytes - (signed_word)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_bytes_allocd - (signed_word)GC_bytes_freed + (signed_word)GC_finalizer_bytes_freed - expl_managed; if (result > (signed_word)GC_bytes_allocd) { result = GC_bytes_allocd; /* probably client bug or unfortunate scheduling */ } result += GC_bytes_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 (result < (signed_word)(GC_bytes_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_bytes_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]; 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(void){ return(GC_adj_bytes_allocd() >= min_bytes_allocd() || GC_heapsize >= GC_collect_at_heapsize);}void GC_notify_full_gc(void){ if (GC_start_call_back != (void (*) (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(void){ 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) { if (GC_print_stats) { GC_log_printf( "***>Full mark for collection %lu after %ld allocd bytes\n", (unsigned long)GC_gc_no+1, (long)GC_bytes_allocd); } 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 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(GC_stop_func stop_func){ CLOCK_TYPE start_time, current_time; if (GC_dont_gc) return FALSE; if (GC_incremental && GC_collection_in_progress()) { if (GC_print_stats) { GC_log_printf( "GC_try_to_collect_inner: finishing collection in progress\n"); } /* 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(); if (GC_print_stats) { GET_TIME(start_time); GC_log_printf( "Initiating full world-stop collection %lu after %ld allocd bytes\n", (unsigned long)GC_gc_no+1, (long)GC_bytes_allocd); } 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) && !GC_reclaim_all(stop_func, FALSE)) { /* Aborted. So far everything is still consistent. */ return(FALSE); } GC_invalidate_mark_state(); /* Flush mark stack. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -