📄 reclaim.c
字号:
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); \ 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 atomic objects: *//*ARGSUSED*/ptr_t GC_reclaim_uninit4(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); \ 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}/* Finally the one word case, which never requires any clearing: *//*ARGSUSED*/ptr_t GC_reclaim1(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); \ INCR_WORDS(1); \ } 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 += 4) { DO_OBJ(0); DO_OBJ(1); DO_OBJ(2); DO_OBJ(3); p += 4; mark_word >>= 4; } } COUNT_UPDATE return(list);# undef DO_OBJ}#endif /* !SMALL_CONFIG && !USE_MARK_BYTES *//* * Generic procedure to rebuild a free list in hbp. * Also called directly from GC_malloc_many. */ptr_t GC_reclaim_generic(hbp, hhdr, sz, init, list COUNT_PARAM)struct hblk *hbp; /* ptr to current heap block */hdr * hhdr;GC_bool init;ptr_t list;word sz;COUNT_DECL{ ptr_t result = list; GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr); GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */); if (init) { switch(sz) {# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) case 1: /* We now issue the hint even if GC_nearly_full returned */ /* DONT_KNOW. */ result = GC_reclaim1(hbp, hhdr, list COUNT_ARG); break; case 2: result = GC_reclaim_clear2(hbp, hhdr, list COUNT_ARG); break; case 4: result = GC_reclaim_clear4(hbp, hhdr, list COUNT_ARG); break;# endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ default: result = GC_reclaim_clear(hbp, hhdr, sz, list COUNT_ARG); break; } } else { GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */); switch(sz) {# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) case 1: result = GC_reclaim1(hbp, hhdr, list COUNT_ARG); break; case 2: result = GC_reclaim_uninit2(hbp, hhdr, list COUNT_ARG); break; case 4: result = GC_reclaim_uninit4(hbp, hhdr, list COUNT_ARG); break;# endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ default: result = GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_ARG); break; } } if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr); return result;}/* * Restore unmarked small objects in the block pointed to by hbp * to the appropriate object free list. * If entirely empty blocks are to be completely deallocated, then * caller should perform that check. */void GC_reclaim_small_nonempty_block(hbp, report_if_found COUNT_PARAM)register struct hblk *hbp; /* ptr to current heap block */int report_if_found; /* Abort if a reclaimable object is found */COUNT_DECL{ hdr *hhdr = HDR(hbp); word sz = hhdr -> hb_sz; int kind = hhdr -> hb_obj_kind; struct obj_kind * ok = &GC_obj_kinds[kind]; ptr_t * flh = &(ok -> ok_freelist[sz]); hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no; if (report_if_found) { GC_reclaim_check(hbp, hhdr, sz); } else { *flh = GC_reclaim_generic(hbp, hhdr, sz, (ok -> ok_init || GC_debugging_started), *flh MEM_FOUND_ADDR); }}/* * Restore an unmarked large object or an entirely empty blocks of small objects * to the heap block free list. * Otherwise enqueue the block for later processing * by GC_reclaim_small_nonempty_block. * If report_if_found is TRUE, then process any block immediately, and * simply report free objects; do not actually reclaim them. */# if defined(__STDC__) || defined(__cplusplus) void GC_reclaim_block(register struct hblk *hbp, word report_if_found)# else void GC_reclaim_block(hbp, report_if_found) register struct hblk *hbp; /* ptr to current heap block */ word report_if_found; /* Abort if a reclaimable object is found */# endif{ register hdr * hhdr; register word sz; /* size of objects in current block */ register struct obj_kind * ok; struct hblk ** rlh; hhdr = HDR(hbp); sz = hhdr -> hb_sz; ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; if( sz > MAXOBJSZ ) { /* 1 big object */ if( !mark_bit_from_hdr(hhdr, 0) ) { if (report_if_found) { FOUND_FREE(hbp, 0); } else { word blocks = OBJ_SZ_TO_BLOCKS(sz); if (blocks > 1) { GC_large_allocd_bytes -= blocks * HBLKSIZE; }# ifdef GATHERSTATS GC_mem_found += sz;# endif GC_freehblk(hbp); } } } else { GC_bool empty = GC_block_empty(hhdr); if (report_if_found) { GC_reclaim_small_nonempty_block(hbp, (int)report_if_found MEM_FOUND_ADDR); } else if (empty) {# ifdef GATHERSTATS GC_mem_found += BYTES_TO_WORDS(HBLKSIZE);# endif GC_freehblk(hbp); } else if (TRUE != GC_block_nearly_full(hhdr)){ /* group of smaller objects, enqueue the real work */ rlh = &(ok -> ok_reclaim_list[sz]); hhdr -> hb_next = *rlh; *rlh = hbp; } /* else not worth salvaging. */ /* We used to do the nearly_full check later, but we */ /* already have the right cache context here. Also */ /* doing it here avoids some silly lock contention in */ /* GC_malloc_many. */ }}#if !defined(NO_DEBUGGING)/* Routines to gather and print heap block info *//* intended for debugging. Otherwise should be called *//* with lock. */struct Print_stats{ size_t number_of_blocks; size_t total_bytes;};#ifdef USE_MARK_BYTES/* Return the number of set mark bits in the given header */int GC_n_set_marks(hhdr)hdr * hhdr;{ register int result = 0; register int i; for (i = 0; i < MARK_BITS_SZ; i++) { result += hhdr -> hb_marks[i]; } return(result);}#else/* Number of set bits in a word. Not performance critical. */static int set_bits(n)word n;{ register word m = n; register int result = 0; while (m > 0) { if (m & 1) result++; m >>= 1; } return(result);}/* Return the number of set mark bits in the given header */int GC_n_set_marks(hhdr)hdr * hhdr;{ register int result = 0; register int i; for (i = 0; i < MARK_BITS_SZ; i++) { result += set_bits(hhdr -> hb_marks[i]); } return(result);}#endif /* !USE_MARK_BYTES *//*ARGSUSED*/# if defined(__STDC__) || defined(__cplusplus) void GC_print_block_descr(struct hblk *h, word dummy)# else void GC_print_block_descr(h, dummy) struct hblk *h; word dummy;# endif{ register hdr * hhdr = HDR(h); register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz); struct Print_stats *ps; GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind), (unsigned long)bytes, (unsigned long)(GC_n_set_marks(hhdr))); bytes += HBLKSIZE-1; bytes &= ~(HBLKSIZE-1); ps = (struct Print_stats *)dummy; ps->total_bytes += bytes; ps->number_of_blocks++;}void GC_print_block_list(){ struct Print_stats pstats; GC_printf1("(kind(0=ptrfree,1=normal,2=unc.,%lu=stubborn):size_in_bytes, #_marks_set)\n", STUBBORN); pstats.number_of_blocks = 0; pstats.total_bytes = 0; GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats); GC_printf2("\nblocks = %lu, bytes = %lu\n", (unsigned long)pstats.number_of_blocks, (unsigned long)pstats.total_bytes);}#endif /* NO_DEBUGGING *//* * Clear all obj_link pointers in the list of free objects *flp. * Clear *flp. * This must be done before dropping a list of free gcj-style objects, * since may otherwise end up with dangling "descriptor" pointers. * It may help for other pointer-containing objects. */void GC_clear_fl_links(flp)ptr_t *flp;{ ptr_t next = *flp; while (0 != next) { *flp = 0; flp = &(obj_link(next)); next = *flp; }}/* * Perform GC_reclaim_block on the entire heap, after first clearing * small object free lists (if we are not just looking for leaks). */void GC_start_reclaim(report_if_found)int report_if_found; /* Abort if a GC_reclaimable object is found */{ int kind; # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) GC_ASSERT(0 == GC_fl_builder_count);# endif /* Clear reclaim- and free-lists */ for (kind = 0; kind < GC_n_kinds; kind++) { ptr_t *fop; ptr_t *lim; struct hblk ** rlp; struct hblk ** rlim; struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list; GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0); if (rlist == 0) continue; /* This kind not used. */ if (!report_if_found) { lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]); for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) { if (*fop != 0) { if (should_clobber) { GC_clear_fl_links(fop); } else { *fop = 0; } } } } /* otherwise free list objects are marked, */ /* and its safe to leave them */ rlim = rlist + MAXOBJSZ+1; for( rlp = rlist; rlp < rlim; rlp++ ) { *rlp = 0; } } # ifdef PRINTBLOCKS GC_printf0("GC_reclaim: current block sizes:\n"); GC_print_block_list();# endif /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */ /* or enqueue the block for later processing. */ GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found);# ifdef EAGER_SWEEP /* This is a very stupid thing to do. We make it possible anyway, */ /* so that you can convince yourself that it really is very stupid. */ GC_reclaim_all((GC_stop_func)0, FALSE);# endif# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) GC_ASSERT(0 == GC_fl_builder_count);# endif }/* * Sweep blocks of the indicated object size and kind until either the * appropriate free list is nonempty, or there are no more blocks to * sweep. */void GC_continue_reclaim(sz, kind)word sz; /* words */int kind;{ register hdr * hhdr; register struct hblk * hbp; register struct obj_kind * ok = &(GC_obj_kinds[kind]); struct hblk ** rlh = ok -> ok_reclaim_list; ptr_t *flh = &(ok -> ok_freelist[sz]); if (rlh == 0) return; /* No blocks of this kind. */ rlh += sz; while ((hbp = *rlh) != 0) { hhdr = HDR(hbp); *rlh = hhdr -> hb_next; GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR); if (*flh != 0) break; }}/* * Reclaim all small blocks waiting to be reclaimed. * Abort and return FALSE when/if (*stop_func)() returns TRUE. * If this returns TRUE, then it's safe to restart the world * with incorrectly cleared mark bits. * If ignore_old is TRUE, then reclaim only blocks that have been * recently reclaimed, and discard the rest. * Stop_func may be 0. */GC_bool GC_reclaim_all(stop_func, ignore_old)GC_stop_func stop_func;GC_bool ignore_old;{ register word sz; register int kind; register hdr * hhdr; register struct hblk * hbp; register struct obj_kind * ok; struct hblk ** rlp; struct hblk ** rlh;# ifdef PRINTTIMES CLOCK_TYPE start_time; CLOCK_TYPE done_time; GET_TIME(start_time);# endif for (kind = 0; kind < GC_n_kinds; kind++) { ok = &(GC_obj_kinds[kind]); rlp = ok -> ok_reclaim_list; if (rlp == 0) continue; for (sz = 1; sz <= MAXOBJSZ; sz++) { rlh = rlp + sz; while ((hbp = *rlh) != 0) { if (stop_func != (GC_stop_func)0 && (*stop_func)()) { return(FALSE); } hhdr = HDR(hbp); *rlh = hhdr -> hb_next; if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) { /* It's likely we'll need it this time, too */ /* It's been touched recently, so this */ /* shouldn't trigger paging. */ GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR); } } } }# ifdef PRINTTIMES GET_TIME(done_time); GC_printf1("Disposing of reclaim lists took %lu msecs\n", MS_TIME_DIFF(done_time,start_time));# endif return(TRUE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -