static void major_dump_heap (FILE *heap_dump_file) { MSBlockInfo *block; int *slots_available = alloca (sizeof (int) * num_block_obj_sizes); int *slots_used = alloca (sizeof (int) * num_block_obj_sizes); int i; for (i = 0; i < num_block_obj_sizes; ++i) slots_available [i] = slots_used [i] = 0; FOREACH_BLOCK (block) { int index = ms_find_block_obj_size_index (block->obj_size); int count = MS_BLOCK_FREE / block->obj_size; slots_available [index] += count; for (i = 0; i < count; ++i) { if (MS_OBJ_ALLOCED (MS_BLOCK_OBJ (block, i), block)) ++slots_used [index]; } } END_FOREACH_BLOCK; fprintf (heap_dump_file, "<occupancies>\n"); for (i = 0; i < num_block_obj_sizes; ++i) { fprintf (heap_dump_file, "<occupancy size=\"%d\" available=\"%d\" used=\"%d\" />\n", block_obj_sizes [i], slots_available [i], slots_used [i]); } fprintf (heap_dump_file, "</occupancies>\n"); FOREACH_BLOCK (block) { int count = MS_BLOCK_FREE / block->obj_size; int i; int start = -1; fprintf (heap_dump_file, "<section type=\"%s\" size=\"%zu\">\n", "old", (size_t)MS_BLOCK_FREE); for (i = 0; i <= count; ++i) { if ((i < count) && MS_OBJ_ALLOCED (MS_BLOCK_OBJ (block, i), block)) { if (start < 0) start = i; } else { if (start >= 0) { mono_sgen_dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), block->block); start = -1; } } } fprintf (heap_dump_file, "</section>\n"); } END_FOREACH_BLOCK; }
static void major_dump_heap (FILE *heap_dump_file) { MSBlockInfo *block; FOREACH_BLOCK (block) { int count = MS_BLOCK_FREE / block->obj_size; int i; int start = -1; fprintf (heap_dump_file, "<section type=\"%s\" size=\"%zu\">\n", "old", (size_t)MS_BLOCK_FREE); for (i = 0; i <= count; ++i) { if ((i < count) && MS_OBJ_ALLOCED (MS_BLOCK_OBJ (block, i), block)) { if (start < 0) start = i; } else { if (start >= 0) { mono_sgen_dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), block->block); start = -1; } } } fprintf (heap_dump_file, "</section>\n"); } END_FOREACH_BLOCK; }
static void consistency_check (void) { MSBlockInfo *block; int i; /* check all blocks */ FOREACH_BLOCK (block) { int count = MS_BLOCK_FREE / block->obj_size; int num_free = 0; void **free; #ifndef FIXED_HEAP /* check block header */ g_assert (((MSBlockHeader*)block->block)->info == block); #endif /* count number of free slots */ for (i = 0; i < count; ++i) { void **obj = (void**) MS_BLOCK_OBJ (block, i); if (!MS_OBJ_ALLOCED (obj, block)) ++num_free; } /* check free list */ for (free = block->free_list; free; free = (void**)*free) { g_assert (MS_BLOCK_FOR_OBJ (free) == block); --num_free; } g_assert (num_free == 0); /* check all mark words are zero */ for (i = 0; i < MS_NUM_MARK_WORDS; ++i) g_assert (block->mark_words [i] == 0); } END_FOREACH_BLOCK; /* check free blocks */ for (i = 0; i < num_block_obj_sizes; ++i) { int j; for (j = 0; j < MS_BLOCK_TYPE_MAX; ++j) check_block_free_list (free_block_lists [j][i], block_obj_sizes [i], j & MS_BLOCK_FLAG_PINNED); } check_empty_blocks (); }
/* * We're not freeing the block if it's empty. We leave that work for * the next major collection. * * This is just called from the domain clearing code, which runs in a * single thread and has the GC lock, so we don't need an extra lock. */ static void free_object (char *obj, size_t size, gboolean pinned) { MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj); int word, bit; DEBUG (9, g_assert ((pinned && block->pinned) || (!pinned && !block->pinned))); DEBUG (9, g_assert (MS_OBJ_ALLOCED (obj, block))); MS_CALC_MARK_BIT (word, bit, obj); DEBUG (9, g_assert (!MS_MARK_BIT (block, word, bit))); if (!block->free_list) { MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, block->has_references); int size_index = MS_BLOCK_OBJ_SIZE_INDEX (size); DEBUG (9, g_assert (!block->next_free)); block->next_free = free_blocks [size_index]; free_blocks [size_index] = block; } memset (obj, 0, size); *(void**)obj = block->free_list; block->free_list = (void**)obj; }
static void major_iterate_objects (gboolean non_pinned, gboolean pinned, IterateObjectCallbackFunc callback, void *data) { MSBlockInfo *block; FOREACH_BLOCK (block) { int count = MS_BLOCK_FREE / block->obj_size; int i; if (block->pinned && !pinned) continue; if (!block->pinned && !non_pinned) continue; for (i = 0; i < count; ++i) { void **obj = (void**) MS_BLOCK_OBJ (block, i); if (MS_OBJ_ALLOCED (obj, block)) callback ((char*)obj, block->obj_size, data); } } END_FOREACH_BLOCK; }
static void major_sweep (void) { int i; #ifdef FIXED_HEAP int j; #else MSBlockInfo **iter; #endif /* clear all the free lists */ for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i) { MSBlockInfo **free_blocks = free_block_lists [i]; int j; for (j = 0; j < num_block_obj_sizes; ++j) free_blocks [j] = NULL; } /* traverse all blocks, free and zero unmarked objects */ #ifdef FIXED_HEAP for (j = 0; j < ms_heap_num_blocks; ++j) { MSBlockInfo *block = &block_infos [j]; #else iter = &all_blocks; while (*iter) { MSBlockInfo *block = *iter; #endif int count; gboolean have_live = FALSE; int obj_index; #ifdef FIXED_HEAP if (!block->used) continue; #endif count = MS_BLOCK_FREE / block->obj_size; block->free_list = NULL; for (obj_index = 0; obj_index < count; ++obj_index) { int word, bit; void *obj = MS_BLOCK_OBJ (block, obj_index); MS_CALC_MARK_BIT (word, bit, obj); if (MS_MARK_BIT (block, word, bit)) { DEBUG (9, g_assert (MS_OBJ_ALLOCED (obj, block))); have_live = TRUE; } else { /* an unmarked object */ if (MS_OBJ_ALLOCED (obj, block)) { binary_protocol_empty (obj, block->obj_size); memset (obj, 0, block->obj_size); } *(void**)obj = block->free_list; block->free_list = obj; } } /* reset mark bits */ memset (block->mark_words, 0, sizeof (mword) * MS_NUM_MARK_WORDS); /* * FIXME: reverse free list so that it's in address * order */ if (have_live) { #ifndef FIXED_HEAP iter = &block->next; #endif /* * If there are free slots in the block, add * the block to the corresponding free list. */ if (block->free_list) { MSBlockInfo **free_blocks = FREE_BLOCKS (block->pinned, block->has_references); int index = MS_BLOCK_OBJ_SIZE_INDEX (block->obj_size); block->next_free = free_blocks [index]; free_blocks [index] = block; } } else { /* * Blocks without live objects are removed from the * block list and freed. */ #ifdef FIXED_HEAP ms_free_block (block); #else *iter = block->next; ms_free_block (block->block); mono_sgen_free_internal (block, INTERNAL_MEM_MS_BLOCK_INFO); #endif --num_major_sections; } } } static int count_pinned_ref; static int count_pinned_nonref; static int count_nonpinned_ref; static int count_nonpinned_nonref; static void count_nonpinned_callback (char *obj, size_t size, void *data) { MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj); if (vtable->klass->has_references) ++count_nonpinned_ref; else ++count_nonpinned_nonref; }
static void ms_sweep (void) { int i; MSBlockInfo **iter; /* statistics for evacuation */ int *slots_available = alloca (sizeof (int) * num_block_obj_sizes); int *slots_used = alloca (sizeof (int) * num_block_obj_sizes); int *num_blocks = alloca (sizeof (int) * num_block_obj_sizes); for (i = 0; i < num_block_obj_sizes; ++i) slots_available [i] = slots_used [i] = num_blocks [i] = 0; /* clear all the free lists */ for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i) { MSBlockInfo **free_blocks = free_block_lists [i]; int j; for (j = 0; j < num_block_obj_sizes; ++j) free_blocks [j] = NULL; } /* traverse all blocks, free and zero unmarked objects */ iter = &all_blocks; while (*iter) { MSBlockInfo *block = *iter; int count; gboolean have_live = FALSE; gboolean has_pinned; int obj_index; int obj_size_index; obj_size_index = block->obj_size_index; has_pinned = block->has_pinned; block->has_pinned = block->pinned; block->is_to_space = FALSE; count = MS_BLOCK_FREE / block->obj_size; block->free_list = NULL; for (obj_index = 0; obj_index < count; ++obj_index) { int word, bit; void *obj = MS_BLOCK_OBJ (block, obj_index); MS_CALC_MARK_BIT (word, bit, obj); if (MS_MARK_BIT (block, word, bit)) { DEBUG (9, g_assert (MS_OBJ_ALLOCED (obj, block))); have_live = TRUE; if (!has_pinned) ++slots_used [obj_size_index]; } else { /* an unmarked object */ if (MS_OBJ_ALLOCED (obj, block)) { binary_protocol_empty (obj, block->obj_size); memset (obj, 0, block->obj_size); } *(void**)obj = block->free_list; block->free_list = obj; } } /* reset mark bits */ memset (block->mark_words, 0, sizeof (mword) * MS_NUM_MARK_WORDS); /* * FIXME: reverse free list so that it's in address * order */ if (have_live) { if (!has_pinned) { ++num_blocks [obj_size_index]; slots_available [obj_size_index] += count; } iter = &block->next; /* * If there are free slots in the block, add * the block to the corresponding free list. */ if (block->free_list) { MSBlockInfo **free_blocks = FREE_BLOCKS (block->pinned, block->has_references); int index = MS_BLOCK_OBJ_SIZE_INDEX (block->obj_size); block->next_free = free_blocks [index]; free_blocks [index] = block; } update_heap_boundaries_for_block (block); } else { /* * Blocks without live objects are removed from the * block list and freed. */ *iter = block->next; #ifdef FIXED_HEAP ms_free_block (block); #else ms_free_block (block->block); mono_sgen_free_internal (block, INTERNAL_MEM_MS_BLOCK_INFO); #endif --num_major_sections; } } for (i = 0; i < num_block_obj_sizes; ++i) { float usage = (float)slots_used [i] / (float)slots_available [i]; if (num_blocks [i] > 5 && usage < evacuation_threshold) { evacuate_block_obj_sizes [i] = TRUE; /* g_print ("slot size %d - %d of %d used\n", block_obj_sizes [i], slots_used [i], slots_available [i]); */ } else { evacuate_block_obj_sizes [i] = FALSE; } } have_swept = TRUE; }