📄 reclaim.c
字号:
/* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. * Copyright (c) 1996-1999 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 <stdio.h>#include "private/gc_priv.h"signed_word GC_mem_found = 0; /* Number of words of memory reclaimed */#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) word GC_fl_builder_count = 0; /* Number of threads currently building free lists without */ /* holding GC lock. It is not safe to collect if this is */ /* nonzero. */#endif /* PARALLEL_MARK *//* We defer printing of leaked objects until we're done with the GC *//* cycle, since the routine for printing objects needs to run outside *//* the collector, e.g. without the allocation lock. */#define MAX_LEAKED 40ptr_t GC_leaked[MAX_LEAKED];unsigned GC_n_leaked = 0;GC_bool GC_have_errors = FALSE;void GC_add_leaked(leaked)ptr_t leaked;{ if (GC_n_leaked < MAX_LEAKED) { GC_have_errors = TRUE; GC_leaked[GC_n_leaked++] = leaked; /* Make sure it's not reclaimed this cycle */ GC_set_mark_bit(leaked); }}static GC_bool printing_errors = FALSE;/* Print all objects on the list after printing any smashed objs. *//* Clear both lists. */void GC_print_all_errors (){ unsigned i; LOCK(); if (printing_errors) { UNLOCK(); return; } printing_errors = TRUE; UNLOCK(); if (GC_debugging_started) GC_print_all_smashed(); for (i = 0; i < GC_n_leaked; ++i) { ptr_t p = GC_leaked[i]; if (HDR(p) -> hb_obj_kind == PTRFREE) { GC_err_printf0("Leaked atomic object at "); } else { GC_err_printf0("Leaked composite object at "); } GC_print_heap_obj(p); GC_err_printf0("\n"); GC_free(p); GC_leaked[i] = 0; } GC_n_leaked = 0; printing_errors = FALSE;}# define FOUND_FREE(hblk, word_no) \ { \ GC_add_leaked((ptr_t)hblk + WORDS_TO_BYTES(word_no)); \ }/* * reclaim phase * *//* * Test whether a block is completely empty, i.e. contains no marked * objects. This does not require the block to be in physical * memory. */ GC_bool GC_block_empty(hhdr)register hdr * hhdr;{ /* We treat hb_marks as an array of words here, even if it is */ /* actually an array of bytes. Since we only check for zero, there */ /* are no endian-ness issues. */ register word *p = (word *)(&(hhdr -> hb_marks[0])); register word * plim = (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ])); while (p < plim) { if (*p++) return(FALSE); } return(TRUE);}/* The following functions sometimes return a DONT_KNOW value. */#define DONT_KNOW 2#ifdef SMALL_CONFIG# define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW# define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW# define GC_block_nearly_full(hhdr) DONT_KNOW#endif#if !defined(SMALL_CONFIG) && defined(USE_MARK_BYTES)# define GC_block_nearly_full1(hhdr, pat1) GC_block_nearly_full(hhdr)# define GC_block_nearly_full3(hhdr, pat1, pat2) GC_block_nearly_full(hhdr) GC_bool GC_block_nearly_full(hhdr)register hdr * hhdr;{ /* We again treat hb_marks as an array of words, even though it */ /* isn't. We first sum up all the words, resulting in a word */ /* containing 4 or 8 separate partial sums. */ /* We then sum the bytes in the word of partial sums. */ /* This is still endian independant. This fails if the partial */ /* sums can overflow. */# if (BYTES_TO_WORDS(MARK_BITS_SZ)) >= 256 --> potential overflow; fix the code# endif register word *p = (word *)(&(hhdr -> hb_marks[0])); register word * plim = (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ])); word sum_vector = 0; unsigned sum; while (p < plim) { sum_vector += *p; ++p; } sum = 0; while (sum_vector > 0) { sum += sum_vector & 0xff; sum_vector >>= 8; } return (sum > BYTES_TO_WORDS(7*HBLKSIZE/8)/(hhdr -> hb_sz));}#endif /* USE_MARK_BYTES */#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)/* * Test whether nearly all of the mark words consist of the same * repeating pattern. */#define FULL_THRESHOLD (MARK_BITS_SZ/16)GC_bool GC_block_nearly_full1(hhdr, pat1)hdr *hhdr;word pat1;{ unsigned i; unsigned misses = 0; GC_ASSERT((MARK_BITS_SZ & 1) == 0); for (i = 0; i < MARK_BITS_SZ; ++i) { if ((hhdr -> hb_marks[i] | ~pat1) != ONES) { if (++misses > FULL_THRESHOLD) return FALSE; } } return TRUE;}/* * Test whether the same repeating 3 word pattern occurs in nearly * all the mark bit slots. * This is used as a heuristic, so we're a bit sloppy and ignore * the last one or two words. */GC_bool GC_block_nearly_full3(hhdr, pat1, pat2, pat3)hdr *hhdr;word pat1, pat2, pat3;{ unsigned i; unsigned misses = 0; if (MARK_BITS_SZ < 4) { return DONT_KNOW; } for (i = 0; i < MARK_BITS_SZ - 2; i += 3) { if ((hhdr -> hb_marks[i] | ~pat1) != ONES) { if (++misses > FULL_THRESHOLD) return FALSE; } if ((hhdr -> hb_marks[i+1] | ~pat2) != ONES) { if (++misses > FULL_THRESHOLD) return FALSE; } if ((hhdr -> hb_marks[i+2] | ~pat3) != ONES) { if (++misses > FULL_THRESHOLD) return FALSE; } } return TRUE;}/* Check whether a small object block is nearly full by looking at only *//* the mark bits. *//* We manually precomputed the mark bit patterns that need to be *//* checked for, and we give up on the ones that are unlikely to occur, *//* or have period > 3. *//* This would be a lot easier with a mark bit per object instead of per *//* word, but that would rewuire computing object numbers in the mark *//* loop, which would require different data structures ... */GC_bool GC_block_nearly_full(hhdr)hdr *hhdr;{ int sz = hhdr -> hb_sz;# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 return DONT_KNOW; /* Shouldn't be used in any standard config. */# endif# if CPP_WORDSZ == 32 switch(sz) { case 1: return GC_block_nearly_full1(hhdr, 0xffffffffl); case 2: return GC_block_nearly_full1(hhdr, 0x55555555l); case 4: return GC_block_nearly_full1(hhdr, 0x11111111l); case 6: return GC_block_nearly_full3(hhdr, 0x41041041l, 0x10410410l, 0x04104104l); case 8: return GC_block_nearly_full1(hhdr, 0x01010101l); case 12: return GC_block_nearly_full3(hhdr, 0x01001001l, 0x10010010l, 0x00100100l); case 16: return GC_block_nearly_full1(hhdr, 0x00010001l); case 32: return GC_block_nearly_full1(hhdr, 0x00000001l); default: return DONT_KNOW; }# endif# if CPP_WORDSZ == 64 switch(sz) { case 1: return GC_block_nearly_full1(hhdr, 0xffffffffffffffffl); case 2: return GC_block_nearly_full1(hhdr, 0x5555555555555555l); case 4: return GC_block_nearly_full1(hhdr, 0x1111111111111111l); case 6: return GC_block_nearly_full3(hhdr, 0x1041041041041041l, 0x4104104104104104l, 0x0410410410410410l); case 8: return GC_block_nearly_full1(hhdr, 0x0101010101010101l); case 12: return GC_block_nearly_full3(hhdr, 0x1001001001001001l, 0x0100100100100100l, 0x0010010010010010l); case 16: return GC_block_nearly_full1(hhdr, 0x0001000100010001l); case 32: return GC_block_nearly_full1(hhdr, 0x0000000100000001l); default: return DONT_KNOW; }# endif}#endif /* !SMALL_CONFIG && !USE_MARK_BYTES *//* We keep track of reclaimed memory if we are either asked to, or *//* we are using the parallel marker. In the latter case, we assume *//* that most allocation goes through GC_malloc_many for scalability. *//* GC_malloc_many needs the count anyway. */# if defined(GATHERSTATS) || defined(PARALLEL_MARK)# define INCR_WORDS(sz) n_words_found += (sz)# define COUNT_PARAM , count# define COUNT_ARG , count# define COUNT_DECL signed_word * count;# define NWORDS_DECL signed_word n_words_found = 0;# define COUNT_UPDATE *count += n_words_found;# define MEM_FOUND_ADDR , &GC_mem_found# else# define INCR_WORDS(sz)# define COUNT_PARAM# define COUNT_ARG# define COUNT_DECL# define NWORDS_DECL# define COUNT_UPDATE# define MEM_FOUND_ADDR# endif/* * Restore unmarked small objects in h of size sz to the object * free list. Returns the new list. * Clears unmarked objects. *//*ARGSUSED*/ptr_t GC_reclaim_clear(hbp, hhdr, sz, list COUNT_PARAM)register struct hblk *hbp; /* ptr to current heap block */register hdr * hhdr;register ptr_t list;register word sz;COUNT_DECL{ register int word_no; register word *p, *q, *plim; NWORDS_DECL GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp)); p = (word *)(hbp->hb_body); word_no = 0; plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz)); /* go through all words in block */ while( p <= plim ) { if( mark_bit_from_hdr(hhdr, word_no) ) { p += sz; } else { INCR_WORDS(sz); /* object is available - put on list */ obj_link(p) = list; list = ((ptr_t)p); /* Clear object, advance p to next object in the process */ q = p + sz;# ifdef USE_MARK_BYTES GC_ASSERT(!(sz & 1) && !((word)p & (2 * sizeof(word) - 1))); p[1] = 0; p += 2; while (p < q) { CLEAR_DOUBLE(p); p += 2; }# else p++; /* Skip link field */ while (p < q) { *p++ = 0; }# endif } word_no += sz; } COUNT_UPDATE return(list);}#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)/* * A special case for 2 word composite objects (e.g. cons cells): *//*ARGSUSED*/ptr_t GC_reclaim_clear2(hbp, hhdr, list COUNT_PARAM)register struct hblk *hbp; /* ptr to current heap block */hdr * hhdr;register ptr_t list;COUNT_DECL{ register word * mark_word_addr = &(hhdr->hb_marks[0]); register word *p, *plim; register word mark_word; register int i; NWORDS_DECL# define DO_OBJ(start_displ) \ if (!(mark_word & ((word)1 << start_displ))) { \ p[start_displ] = (word)list; \ list = (ptr_t)(p+start_displ); \ p[start_displ+1] = 0; \ INCR_WORDS(2); \ } p = (word *)(hbp->hb_body); plim = (word *)(((word)hbp) + HBLKSIZE); /* go through all words in block */ while( p < plim ) { mark_word = *mark_word_addr++; for (i = 0; i < WORDSZ; i += 8) { DO_OBJ(0); DO_OBJ(2); DO_OBJ(4); DO_OBJ(6); p += 8; mark_word >>= 8; } } COUNT_UPDATE return(list);# undef DO_OBJ}/* * Another special case for 4 word composite objects: *//*ARGSUSED*/ptr_t GC_reclaim_clear4(hbp, hhdr, list COUNT_PARAM)register struct hblk *hbp; /* ptr to current heap block */hdr * hhdr;register ptr_t list;COUNT_DECL{ register word * mark_word_addr = &(hhdr->hb_marks[0]); register word *p, *plim; register word mark_word; NWORDS_DECL# define DO_OBJ(start_displ) \ if (!(mark_word & ((word)1 << start_displ))) { \ p[start_displ] = (word)list; \ list = (ptr_t)(p+start_displ); \ p[start_displ+1] = 0; \ CLEAR_DOUBLE(p + start_displ + 2); \ INCR_WORDS(4); \ } p = (word *)(hbp->hb_body); plim = (word *)(((word)hbp) + HBLKSIZE); /* go through all words in block */ while( p < plim ) { mark_word = *mark_word_addr++; DO_OBJ(0); DO_OBJ(4); DO_OBJ(8); DO_OBJ(12); DO_OBJ(16); DO_OBJ(20); DO_OBJ(24); DO_OBJ(28);# if CPP_WORDSZ == 64 DO_OBJ(32); DO_OBJ(36); DO_OBJ(40); DO_OBJ(44); DO_OBJ(48); DO_OBJ(52); DO_OBJ(56); DO_OBJ(60);# endif p += WORDSZ; } COUNT_UPDATE return(list);# undef DO_OBJ}#endif /* !SMALL_CONFIG && !USE_MARK_BYTES *//* The same thing, but don't clear objects: *//*ARGSUSED*/ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_PARAM)register struct hblk *hbp; /* ptr to current heap block */register hdr * hhdr;register ptr_t list;register word sz;COUNT_DECL{ register int word_no = 0; register word *p, *plim; NWORDS_DECL p = (word *)(hbp->hb_body); plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz)); /* go through all words in block */ while( p <= plim ) { if( !mark_bit_from_hdr(hhdr, word_no) ) { INCR_WORDS(sz); /* object is available - put on list */ obj_link(p) = list; list = ((ptr_t)p); } p += sz; word_no += sz; } COUNT_UPDATE return(list);}/* Don't really reclaim objects, just check for unmarked ones: *//*ARGSUSED*/void GC_reclaim_check(hbp, hhdr, sz)register struct hblk *hbp; /* ptr to current heap block */register hdr * hhdr;register word sz;{ register int word_no = 0; register word *p, *plim;# ifdef GATHERSTATS register int n_words_found = 0;# endif p = (word *)(hbp->hb_body); plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz)); /* go through all words in block */ while( p <= plim ) { if( !mark_bit_from_hdr(hhdr, word_no) ) { FOUND_FREE(hbp, word_no); } p += sz; word_no += sz; }}#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)/* * Another special case for 2 word atomic objects: *//*ARGSUSED*/ptr_t GC_reclaim_uninit2(hbp, hhdr, list COUNT_PARAM)register struct hblk *hbp; /* ptr to current heap block */hdr * hhdr;register ptr_t list;COUNT_DECL{ register word * mark_word_addr = &(hhdr->hb_marks[0]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -