#include <math.h>
#define MS_BLOCK_SIZE (16*1024)
+#define MAJOR_SECTION_SIZE MS_BLOCK_SIZE
/*
* Don't allocate single blocks, but alloc a contingent of this many
#define MS_BLOCK_FREE (MS_BLOCK_SIZE - MS_BLOCK_SKIP)
-#define MS_NUM_MARK_WORDS(c) (((c) + sizeof (mword) * 8 - 1) / (sizeof (mword) * 8))
+#define MS_NUM_MARK_WORDS ((MS_BLOCK_SIZE / ALLOC_ALIGN + sizeof (mword) * 8 - 1) / (sizeof (mword) * 8))
#if MAX_SMALL_OBJ_SIZE > MS_BLOCK_FREE / 2
#error MAX_SMALL_OBJ_SIZE must be at most (MS_BLOCK_SIZE - MS_BLOCK_SKIP) / 2
struct _MSBlockInfo {
int obj_size;
gboolean pinned;
+ gboolean has_references;
char *block;
void **free_list;
MSBlockInfo *next_free;
MSBlockInfo *next;
int pin_queue_start;
int pin_queue_end;
- mword mark_words [1];
+ mword mark_words [MS_NUM_MARK_WORDS];
};
#define MS_BLOCK_OBJ(b,i) ((b)->block + MS_BLOCK_SKIP + (b)->obj_size * (i))
#define MS_BLOCK_OBJ_INDEX(o,b) (((char*)(o) - ((b)->block + MS_BLOCK_SKIP)) / (b)->obj_size)
-#define MS_CALC_MARK_BIT(w,b,i) do { \
- if (sizeof (mword) == 4) { \
- (w) = (i) >> 5; \
- (b) = (i) & 31; \
- } else { \
- (w) = (i) >> 6; \
- (b) = (i) & 63; \
- } \
+#define MS_CALC_MARK_BIT(w,b,o,bl) do { \
+ int i = ((char*)(o) - (bl)->block) >> ALLOC_ALIGN_BITS; \
+ if (sizeof (mword) == 4) { \
+ (w) = i >> 5; \
+ (b) = i & 31; \
+ } else { \
+ (w) = i >> 6; \
+ (b) = i & 63; \
+ } \
} while (0)
#define MS_MARK_BIT(bl,w,b) ((bl)->mark_words [(w)] & (1L << (b)))
#define MS_BLOCK_OBJ_SIZE_FACTOR (sqrt (2.0))
-#define MIN_MINOR_COLLECTION_SECTION_ALLOWANCE (DEFAULT_NURSERY_SIZE * 3 / MS_BLOCK_SIZE)
-
-static int minor_collection_section_allowance;
-static int minor_collection_sections_alloced = 0;
-
/*
* This way we can lookup block object size indexes for sizes up to
* 256 bytes with a single load.
static int num_block_obj_sizes;
static int fast_block_obj_size_indexes [MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES];
+#define MS_BLOCK_FLAG_PINNED 1
+#define MS_BLOCK_FLAG_REFS 2
+
+#define MS_BLOCK_TYPE_MAX 4
+
/* all blocks in the system */
static MSBlockInfo *all_blocks;
static int num_major_sections = 0;
/* one free block list for each block object size */
-static MSBlockInfo **free_non_pinned_blocks;
-static MSBlockInfo **free_pinned_blocks;
+static MSBlockInfo **free_block_lists [MS_BLOCK_TYPE_MAX];
static long stat_major_blocks_alloced = 0;
static long stat_major_blocks_freed = 0;
g_assert_not_reached ();
}
-#define FREE_BLOCKS(pinned) ((pinned) ? free_pinned_blocks : free_non_pinned_blocks)
+#define FREE_BLOCKS(p,r) (free_block_lists [((p) ? MS_BLOCK_FLAG_PINNED : 0) | ((r) ? MS_BLOCK_FLAG_REFS : 0)])
#define MS_BLOCK_OBJ_SIZE_INDEX(s) \
(((s)+7)>>3 < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES ? \
g_assert (!((mword)block & (MS_BLOCK_SIZE - 1)));
+ UPDATE_HEAP_BOUNDARIES (block, (char*)block + MS_BLOCK_SIZE);
+
return block;
}
++num_empty_blocks;
}
+//#define MARKSWEEP_CONSISTENCY_CHECK
+
+#ifdef MARKSWEEP_CONSISTENCY_CHECK
static void
check_block_free_list (MSBlockInfo *block, int size, gboolean pinned)
{
/* check all blocks */
for (block = all_blocks; block; block = block->next) {
int count = MS_BLOCK_FREE / block->obj_size;
- int num_mark_words = MS_NUM_MARK_WORDS (count);
int num_free = 0;
void **free;
g_assert (num_free == 0);
/* check all mark words are zero */
- for (i = 0; i < num_mark_words; ++i)
+ for (i = 0; i < MS_NUM_MARK_WORDS; ++i)
g_assert (block->mark_words [i] == 0);
}
/* check free blocks */
for (i = 0; i < num_block_obj_sizes; ++i) {
- check_block_free_list (free_non_pinned_blocks [i], block_obj_sizes [i], FALSE);
- check_block_free_list (free_pinned_blocks [i], block_obj_sizes [i], TRUE);
+ 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);
}
}
+#endif
static void
-ms_alloc_block (int size_index, gboolean pinned)
+ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
{
int size = block_obj_sizes [size_index];
int count = MS_BLOCK_FREE / size;
- int num_mark_words = MS_NUM_MARK_WORDS (count);
- int block_info_size = sizeof (MSBlockInfo) + sizeof (mword) * (num_mark_words - 1);
- MSBlockInfo *info = get_internal_mem (block_info_size, INTERNAL_MEM_MS_BLOCK_INFO);
+ MSBlockInfo *info = get_internal_mem (sizeof (MSBlockInfo), INTERNAL_MEM_MS_BLOCK_INFO);
MSBlockHeader *header;
- MSBlockInfo **free_blocks = FREE_BLOCKS (pinned);
+ MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references);
char *obj_start;
int i;
info->obj_size = size;
info->pinned = pinned;
+ info->has_references = has_references;
info->block = ms_get_empty_block ();
header = (MSBlockHeader*) info->block;
}
static void*
-alloc_obj (int size, gboolean pinned)
+alloc_obj (int size, gboolean pinned, gboolean has_references)
{
int size_index = MS_BLOCK_OBJ_SIZE_INDEX (size);
- MSBlockInfo **free_blocks = FREE_BLOCKS (pinned);
+ MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references);
MSBlockInfo *block;
void *obj;
if (!free_blocks [size_index])
- ms_alloc_block (size_index, pinned);
+ ms_alloc_block (size_index, pinned, has_references);
block = free_blocks [size_index];
DEBUG (9, g_assert (block));
}
static void*
-ms_alloc_obj (int size)
+ms_alloc_obj (int size, gboolean has_references)
{
- return alloc_obj (size, FALSE);
+ return alloc_obj (size, FALSE, has_references);
}
/* FIXME: inline fast path */
-#define MAJOR_GET_COPY_OBJECT_SPACE(dest, size) do { \
- (dest) = ms_alloc_obj ((size)); \
+#define MAJOR_GET_COPY_OBJECT_SPACE(dest, size, refs) do { \
+ (dest) = ms_alloc_obj ((size), (refs)); \
} while (0)
/*
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, MS_BLOCK_OBJ_INDEX (obj, block));
+ MS_CALC_MARK_BIT (word, bit, obj, block);
DEBUG (9, g_assert (!MS_MARK_BIT (block, word, bit)));
if (!block->free_list) {
- MSBlockInfo **free_blocks = FREE_BLOCKS (pinned);
+ 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];
/* size is a multiple of ALLOC_ALIGN */
static void*
-major_alloc_small_pinned_obj (size_t size)
+major_alloc_small_pinned_obj (size_t size, gboolean has_references)
{
- return alloc_obj (size, TRUE);
+ return alloc_obj (size, TRUE, has_references);
}
static void
* size is already rounded up and we hold the GC lock.
*/
static void*
-alloc_degraded (MonoVTable *vtable, size_t size)
+major_alloc_degraded (MonoVTable *vtable, size_t size)
{
- void *obj = alloc_obj (size, FALSE);
+ void *obj;
+ int old_num_sections = num_major_sections;
+ obj = alloc_obj (size, FALSE, vtable->klass->has_references);
*(MonoVTable**)obj = vtable;
+ HEAVY_STAT (++stat_objects_alloced_degraded);
+ HEAVY_STAT (stat_bytes_alloced_degraded += size);
+ g_assert (num_major_sections >= old_num_sections);
+ minor_collection_sections_alloced += num_major_sections - old_num_sections;
return obj;
}
/* now we know it's in a major block */
block = MS_BLOCK_FOR_OBJ (obj);
DEBUG (9, g_assert (!block->pinned));
- MS_CALC_MARK_BIT (word, bit, MS_BLOCK_OBJ_INDEX (obj, block));
+ MS_CALC_MARK_BIT (word, bit, obj, block);
return MS_MARK_BIT (block, word, bit) ? TRUE : FALSE;
}
}
}
-#define MS_MARK_INDEX_IN_BLOCK_AND_ENQUEUE_CHECKED(obj,block,index) do { \
+#define MS_MARK_OBJECT_AND_ENQUEUE_CHECKED(obj,block) do { \
int __word, __bit; \
- MS_CALC_MARK_BIT (__word, __bit, (index)); \
- DEBUG (9, g_assert ((obj) == MS_BLOCK_OBJ ((block), (index)))); \
+ MS_CALC_MARK_BIT (__word, __bit, (obj), (block)); \
if (!MS_MARK_BIT ((block), __word, __bit) && MS_OBJ_ALLOCED ((obj), (block))) { \
MS_SET_MARK_BIT ((block), __word, __bit); \
- GRAY_OBJECT_ENQUEUE ((obj)); \
+ if ((block)->has_references) \
+ GRAY_OBJECT_ENQUEUE ((obj)); \
binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), safe_object_get_size ((MonoObject*)(obj))); \
} \
} while (0)
-#define MS_MARK_INDEX_IN_BLOCK_AND_ENQUEUE(obj,block,index) do { \
+#define MS_MARK_OBJECT_AND_ENQUEUE(obj,block) do { \
int __word, __bit; \
- MS_CALC_MARK_BIT (__word, __bit, (index)); \
- DEBUG (9, g_assert ((obj) == MS_BLOCK_OBJ ((block), (index)))); \
- g_assert (MS_OBJ_ALLOCED ((obj), (block))); \
+ MS_CALC_MARK_BIT (__word, __bit, (obj), (block)); \
+ DEBUG (9, g_assert (MS_OBJ_ALLOCED ((obj), (block)))); \
if (!MS_MARK_BIT ((block), __word, __bit)) { \
MS_SET_MARK_BIT ((block), __word, __bit); \
- GRAY_OBJECT_ENQUEUE ((obj)); \
+ if ((block)->has_references) \
+ GRAY_OBJECT_ENQUEUE ((obj)); \
binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), safe_object_get_size ((MonoObject*)(obj))); \
} \
} while (0)
void *obj = *ptr;
mword objsize;
MSBlockInfo *block;
- int index;
- int count;
+
+ HEAVY_STAT (++stat_copy_object_called_major);
DEBUG (9, g_assert (obj));
DEBUG (9, g_assert (current_collection_generation == GENERATION_OLD));
if (object_is_pinned (obj))
return;
+ HEAVY_STAT (++stat_objects_copied_major);
+
obj = copy_object_no_checks (obj);
*ptr = obj;
* re-fetch it.
*/
block = MS_BLOCK_FOR_OBJ (obj);
- index = MS_BLOCK_OBJ_INDEX (obj, block);
- DEBUG (9, g_assert (obj == MS_BLOCK_OBJ (block, index)));
- MS_CALC_MARK_BIT (word, bit, (index));
+ MS_CALC_MARK_BIT (word, bit, obj, block);
DEBUG (9, g_assert (!MS_MARK_BIT (block, word, bit)));
MS_SET_MARK_BIT (block, word, bit);
return;
return;
binary_protocol_pin (obj, (gpointer)LOAD_VTABLE (obj), safe_object_get_size ((MonoObject*)obj));
pin_object (obj);
+ /* FIXME: only enqueue if object has references */
GRAY_OBJECT_ENQUEUE (obj);
return;
}
block = MS_BLOCK_FOR_OBJ (obj);
- index = MS_BLOCK_OBJ_INDEX (obj, block);
- count = MS_BLOCK_FREE / block->obj_size;
- DEBUG (9, g_assert (index >= 0 && index < count));
- MS_MARK_INDEX_IN_BLOCK_AND_ENQUEUE (obj, block, index);
+ MS_MARK_OBJECT_AND_ENQUEUE (obj, block);
}
static void
DEBUG (9, g_assert (index >= 0 && index < count));
if (index == last_index)
continue;
- MS_MARK_INDEX_IN_BLOCK_AND_ENQUEUE_CHECKED (MS_BLOCK_OBJ (block, index), block, index);
+ MS_MARK_OBJECT_AND_ENQUEUE_CHECKED (MS_BLOCK_OBJ (block, index), block);
last_index = index;
}
}
static void
major_sweep (void)
{
- MSBlockInfo *empty_blocks = NULL;
MSBlockInfo **iter;
int i;
+ /* 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 = MS_BLOCK_FREE / block->obj_size;
gboolean have_live = FALSE;
- int word_index = 0;
- int obj_index = 0;
+ int obj_index;
block->free_list = NULL;
- do {
- mword word = block->mark_words [word_index];
+ for (obj_index = 0; obj_index < count; ++obj_index) {
+ int word, bit;
+ void *obj = MS_BLOCK_OBJ (block, obj_index);
- if (word == (mword)-1L) {
- obj_index += 8 * sizeof (mword);
+ MS_CALC_MARK_BIT (word, bit, obj, block);
+ if (MS_MARK_BIT (block, word, bit)) {
+ DEBUG (9, g_assert (MS_OBJ_ALLOCED (obj, block)));
have_live = TRUE;
} else {
- int num_bits = MIN (count - obj_index, 8 * sizeof (mword));
- for (i = 0; i < num_bits; ++i) {
- void *obj = MS_BLOCK_OBJ (block, obj_index);
- if (word & 1) {
- DEBUG (9, g_assert (MS_OBJ_ALLOCED (obj, block)));
- have_live = TRUE;
- } else {
- /* an unmarked object */
- void *obj = MS_BLOCK_OBJ (block, obj_index);
- 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;
- }
- word >>= 1;
- ++obj_index;
+ /* 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 */
- block->mark_words [word_index] = 0;
-
- ++word_index;
- } while (obj_index < count);
+ /* reset mark bits */
+ memset (block->mark_words, 0, sizeof (mword) * MS_NUM_MARK_WORDS);
/*
* FIXME: reverse free list so that it's in address
if (have_live) {
iter = &block->next;
- continue;
- }
- /*
- * blocks without live objects are removed from the
- * block list and marked with obj_size = -1
- */
- *iter = block->next;
- block->next = empty_blocks;
- empty_blocks = block;
+ /*
+ * 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.
+ */
+ *iter = block->next;
- block->obj_size = -1;
- }
+ ms_free_block (block->block);
+ free_internal_mem (block, INTERNAL_MEM_MS_BLOCK_INFO);
- /* if there are no blocks to be freed, we're done */
- if (!empty_blocks)
- return;
+ --num_major_sections;
- /* go through all free lists and remove the blocks to be freed */
- for (i = 0; i < num_block_obj_sizes; ++i) {
- int pinned;
- for (pinned = 0; pinned <= 1; ++pinned) {
- MSBlockInfo **free_blocks = FREE_BLOCKS (pinned);
- iter = &(free_blocks [i]);
- while (*iter) {
- MSBlockInfo *block = *iter;
- if (block->obj_size < 0)
- *iter = block->next_free;
- else
- iter = &block->next_free;
- }
+ ++stat_major_blocks_freed;
}
}
+}
- /* now free the blocks */
- while (empty_blocks) {
- MSBlockInfo *next = empty_blocks->next;
-
- ms_free_block (empty_blocks->block);
- free_internal_mem (empty_blocks, INTERNAL_MEM_MS_BLOCK_INFO);
-
- empty_blocks = next;
+static int count_pinned_ref;
+static int count_pinned_nonref;
+static int count_nonpinned_ref;
+static int count_nonpinned_nonref;
- --num_major_sections;
+static void
+count_nonpinned_callback (char *obj, size_t size, void *data)
+{
+ MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj);
- ++stat_major_blocks_freed;
- }
+ if (vtable->klass->has_references)
+ ++count_nonpinned_ref;
+ else
+ ++count_nonpinned_nonref;
}
static void
-major_do_collection (const char *reason)
+count_pinned_callback (char *obj, size_t size, void *data)
{
- LOSObject *bigobj, *prevbo;
- MSBlockInfo *block;
- TV_DECLARE (all_atv);
- TV_DECLARE (all_btv);
- TV_DECLARE (atv);
- TV_DECLARE (btv);
- /* FIXME: only use these values for the precise scan
- * note that to_space pointers should be excluded anyway...
- */
- char *heap_start = NULL;
- char *heap_end = (char*)-1;
- int old_num_major_sections = num_major_sections;
- int num_major_sections_saved, save_target, allowance_target;
-
- //consistency_check ();
-
- init_stats ();
- binary_protocol_collection (GENERATION_OLD);
- check_scan_starts ();
- gray_object_queue_init ();
-
- degraded_mode = 0;
- DEBUG (1, fprintf (gc_debug_file, "Start major collection %d\n", num_major_gcs));
- num_major_gcs++;
- mono_stats.major_gc_count ++;
-
- /* world must be stopped already */
- TV_GETTIME (all_atv);
- TV_GETTIME (atv);
+ MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj);
- /* Pinning depends on this */
- clear_nursery_fragments (nursery_next);
-
- TV_GETTIME (btv);
- time_major_pre_collection_fragment_clear += TV_ELAPSED_MS (atv, btv);
-
- if (xdomain_checks)
- check_for_xdomain_refs ();
-
- nursery_section->next_data = nursery_real_end;
- /* we should also coalesce scanning from sections close to each other
- * and deal with pointers outside of the sections later.
- */
- /* The remsets are not useful for a major collection */
- clear_remsets ();
-
- TV_GETTIME (atv);
- init_pinning ();
- DEBUG (6, fprintf (gc_debug_file, "Collecting pinned addresses\n"));
- pin_from_roots ((void*)lowest_heap_address, (void*)highest_heap_address);
- optimize_pin_queue (0);
-
- /*
- * pin_queue now contains all candidate pointers, sorted and
- * uniqued. We must do two passes now to figure out which
- * objects are pinned.
- *
- * The first is to find within the pin_queue the area for each
- * section. This requires that the pin_queue be sorted. We
- * also process the LOS objects and pinned chunks here.
- *
- * The second, destructive, pass is to reduce the section
- * areas to pointers to the actually pinned objects.
- */
- DEBUG (6, fprintf (gc_debug_file, "Pinning from sections\n"));
- /* first pass for the sections */
- find_section_pin_queue_start_end (nursery_section);
- for (block = all_blocks; block; block = block->next) {
- find_optimized_pin_queue_area (block->block + MS_BLOCK_SKIP, block->block + MS_BLOCK_SIZE,
- &block->pin_queue_start, &block->pin_queue_end);
- }
- /* identify possible pointers to the insize of large objects */
- DEBUG (6, fprintf (gc_debug_file, "Pinning from large objects\n"));
- for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) {
- int start, end;
- find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + bigobj->size, &start, &end);
- if (start != end) {
- pin_object (bigobj->data);
- GRAY_OBJECT_ENQUEUE (bigobj->data);
- if (heap_dump_file)
- pin_stats_register_object ((char*) bigobj->data, safe_object_get_size ((MonoObject*) bigobj->data));
- DEBUG (6, fprintf (gc_debug_file, "Marked large object %p (%s) size: %zd from roots\n", bigobj->data, safe_name (bigobj->data), bigobj->size));
- }
- }
- /* second pass for the sections */
- pin_objects_in_section (nursery_section);
- for (block = all_blocks; block; block = block->next)
- mark_pinned_objects_in_block (block);
-
- TV_GETTIME (btv);
- time_major_pinning += TV_ELAPSED_MS (atv, btv);
- DEBUG (2, fprintf (gc_debug_file, "Finding pinned pointers: %d in %d usecs\n", next_pin_slot, TV_ELAPSED (atv, btv)));
- DEBUG (4, fprintf (gc_debug_file, "Start scan with %d pinned objects\n", next_pin_slot));
-
- drain_gray_stack ();
-
- TV_GETTIME (atv);
- time_major_scan_pinned += TV_ELAPSED_MS (btv, atv);
-
- /* registered roots, this includes static fields */
- scan_from_registered_roots (major_copy_or_mark_object, heap_start, heap_end, ROOT_TYPE_NORMAL);
- scan_from_registered_roots (major_copy_or_mark_object, heap_start, heap_end, ROOT_TYPE_WBARRIER);
- TV_GETTIME (btv);
- time_major_scan_registered_roots += TV_ELAPSED_MS (atv, btv);
-
- /* Threads */
- /* FIXME: This is the wrong place for this, because it does
- pinning */
- scan_thread_data (heap_start, heap_end, TRUE);
- TV_GETTIME (atv);
- time_major_scan_thread_data += TV_ELAPSED_MS (btv, atv);
-
- TV_GETTIME (btv);
- time_major_scan_alloc_pinned += TV_ELAPSED_MS (atv, btv);
-
- /* scan the list of objects ready for finalization */
- scan_finalizer_entries (major_copy_or_mark_object, fin_ready_list);
- scan_finalizer_entries (major_copy_or_mark_object, critical_fin_list);
- TV_GETTIME (atv);
- time_major_scan_finalized += TV_ELAPSED_MS (btv, atv);
- DEBUG (2, fprintf (gc_debug_file, "Root scan: %d usecs\n", TV_ELAPSED (btv, atv)));
-
- TV_GETTIME (btv);
- time_major_scan_big_objects += TV_ELAPSED_MS (atv, btv);
-
- /* all the objects in the heap */
- finish_gray_stack (heap_start, heap_end, GENERATION_OLD);
- TV_GETTIME (atv);
- time_major_finish_gray_stack += TV_ELAPSED_MS (btv, atv);
-
- /* sweep the big objects list */
- prevbo = NULL;
- for (bigobj = los_object_list; bigobj;) {
- if (object_is_pinned (bigobj->data)) {
- unpin_object (bigobj->data);
- } else {
- LOSObject *to_free;
- /* not referenced anywhere, so we can free it */
- if (prevbo)
- prevbo->next = bigobj->next;
- else
- los_object_list = bigobj->next;
- to_free = bigobj;
- bigobj = bigobj->next;
- free_large_object (to_free);
- continue;
- }
- prevbo = bigobj;
- bigobj = bigobj->next;
- }
-
- major_sweep ();
-
- TV_GETTIME (btv);
- time_major_sweep += TV_ELAPSED_MS (atv, btv);
-
- /* walk the pin_queue, build up the fragment list of free memory, unmark
- * pinned objects as we go, memzero() the empty fragments so they are ready for the
- * next allocations.
- */
- build_nursery_fragments (nursery_section->pin_queue_start, nursery_section->pin_queue_end);
-
- TV_GETTIME (atv);
- time_major_fragment_creation += TV_ELAPSED_MS (btv, atv);
-
- TV_GETTIME (all_btv);
- mono_stats.major_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
-
- if (heap_dump_file)
- dump_heap ("major", num_major_gcs - 1, reason);
-
- /* prepare the pin queue for the next collection */
- next_pin_slot = 0;
- if (fin_ready_list || critical_fin_list) {
- DEBUG (4, fprintf (gc_debug_file, "Finalizer-thread wakeup: ready %d\n", num_ready_finalizers));
- mono_gc_finalize_notify ();
- }
- pin_stats_reset ();
-
- g_assert (gray_object_queue_is_empty ());
-
- commit_stats (GENERATION_OLD);
-
- num_major_sections_saved = MAX (old_num_major_sections - num_major_sections, 1);
+ if (vtable->klass->has_references)
+ ++count_pinned_ref;
+ else
+ ++count_pinned_nonref;
+}
- save_target = num_major_sections / 2;
- /*
- * We aim to allow the allocation of as many sections as is
- * necessary to reclaim save_target sections in the next
- * collection. We assume the collection pattern won't change.
- * In the last cycle, we had num_major_sections_saved for
- * minor_collection_sections_alloced. Assuming things won't
- * change, this must be the same ratio as save_target for
- * allowance_target, i.e.
- *
- * num_major_sections_saved save_target
- * --------------------------------- == ----------------
- * minor_collection_sections_alloced allowance_target
- *
- * hence:
- */
- allowance_target = save_target * minor_collection_sections_alloced / num_major_sections_saved;
+static void __attribute__ ((unused))
+count_ref_nonref_objs (void)
+{
+ int total;
- minor_collection_section_allowance = MAX (MIN (allowance_target, num_major_sections), MIN_MINOR_COLLECTION_SECTION_ALLOWANCE);
+ count_pinned_ref = 0;
+ count_pinned_nonref = 0;
+ count_nonpinned_ref = 0;
+ count_nonpinned_nonref = 0;
- minor_collection_sections_alloced = 0;
+ major_iterate_objects (TRUE, FALSE, count_nonpinned_callback, NULL);
+ major_iterate_objects (FALSE, TRUE, count_pinned_callback, NULL);
- check_scan_starts ();
+ total = count_pinned_nonref + count_nonpinned_nonref + count_pinned_ref + count_nonpinned_ref;
- //consistency_check ();
+ g_print ("ref: %d pinned %d non-pinned non-ref: %d pinned %d non-pinned -- %.1f\n",
+ count_pinned_ref, count_nonpinned_ref,
+ count_pinned_nonref, count_nonpinned_nonref,
+ (count_pinned_nonref + count_nonpinned_nonref) * 100.0 / total);
}
static int
}
*/
- free_pinned_blocks = get_internal_mem (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
- free_non_pinned_blocks = get_internal_mem (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+ for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i)
+ free_block_lists [i] = get_internal_mem (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES; ++i)
fast_block_obj_size_indexes [i] = ms_find_block_obj_size_index (i * 8);
mono_counters_register ("# major blocks allocated", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_alloced);
mono_counters_register ("# major blocks freed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_freed);
-
- minor_collection_section_allowance = MIN_MINOR_COLLECTION_SECTION_ALLOWANCE;
}
/* only valid during minor collections */
static void
major_start_nursery_collection (void)
{
- //consistency_check ();
+#ifdef MARKSWEEP_CONSISTENCY_CHECK
+ consistency_check ();
+#endif
old_num_major_sections = num_major_sections;
}
{
int sections_alloced;
- //consistency_check ();
+#ifdef MARKSWEEP_CONSISTENCY_CHECK
+ consistency_check ();
+#endif
sections_alloced = num_major_sections - old_num_major_sections;
minor_collection_sections_alloced += sections_alloced;
}
-static gboolean
-major_need_major_collection (void)
+static void
+major_find_pin_queue_start_ends (void)
+{
+ MSBlockInfo *block;
+
+ for (block = all_blocks; block; block = block->next) {
+ find_optimized_pin_queue_area (block->block + MS_BLOCK_SKIP, block->block + MS_BLOCK_SIZE,
+ &block->pin_queue_start, &block->pin_queue_end);
+ }
+}
+
+static void
+major_pin_objects (void)
+{
+ MSBlockInfo *block;
+
+ for (block = all_blocks; block; block = block->next)
+ mark_pinned_objects_in_block (block);
+}
+
+static void
+major_init_to_space (void)
{
- return minor_collection_sections_alloced > minor_collection_section_allowance;
}
static void