Index: gc.c =================================================================== --- gc.c (revision 45277) +++ gc.c (working copy) @@ -116,6 +116,13 @@ #define GC_HEAP_OLDOBJECT_LIMIT_FACTOR 2.0 #endif +#ifndef GC_HEAP_FREE_SLOTS_MIN_RATIO +#define GC_HEAP_FREE_SLOTS_MIN_RATIO 0.3 +#endif +#ifndef GC_HEAP_FREE_SLOTS_MAX_RATIO +#define GC_HEAP_FREE_SLOTS_MAX_RATIO 0.8 +#endif + #ifndef GC_MALLOC_LIMIT_MIN #define GC_MALLOC_LIMIT_MIN (16 * 1024 * 1024 /* 16MB */) #endif @@ -1161,26 +1168,30 @@ heap_pages_increment = 0; } -static void -heap_set_increment(rb_objspace_t *objspace, size_t minimum_limit) +static size_t +heap_extend_pages(rb_objspace_t *objspace) { size_t used = heap_pages_used - heap_tomb->page_length; size_t next_used_limit = (size_t)(used * gc_params.growth_factor); + if (gc_params.growth_max_slots > 0) { size_t max_used_limit = (size_t)(used + gc_params.growth_max_slots/HEAP_OBJ_LIMIT); if (next_used_limit > max_used_limit) next_used_limit = max_used_limit; } + + return next_used_limit - used; +} + +static void +heap_set_increment(rb_objspace_t *objspace, size_t additional_pages) +{ + size_t used = heap_pages_used - heap_tomb->page_length; + size_t next_used_limit = used + additional_pages; + if (next_used_limit == heap_pages_used) next_used_limit++; - if (next_used_limit < minimum_limit) { - next_used_limit = minimum_limit; - } - heap_pages_increment = next_used_limit - used; heap_pages_expand_sorted(objspace); - - if (0) fprintf(stderr, "heap_set_increment: heap_pages_length: %d, heap_pages_used: %d, heap_pages_increment: %d, next_used_limit: %d\n", - (int)heap_pages_length, (int)heap_pages_used, (int)heap_pages_increment, (int)next_used_limit); } static int @@ -2820,17 +2831,32 @@ rgengc_report(1, objspace, "page_sweep: end.\n"); } -/* allocate additional minimum page to work */ +/* allocate minimum page to work */ static void +gc_heap_allocate_minimum_page(rb_objspace_t *objspace, rb_heap_t *heap) +{ + heap_set_increment(objspace, 1); + if (!heap_increment(objspace, heap)) { /* can't allocate additional free objects */ + during_gc = 0; + rb_memerror(); + } +} + +static void gc_heap_prepare_minimum_pages(rb_objspace_t *objspace, rb_heap_t *heap) { if (!heap->free_pages) { - /* there is no free after page_sweep() */ - heap_set_increment(objspace, 0); - if (!heap_increment(objspace, heap)) { /* can't allocate additional free objects */ - during_gc = 0; - rb_memerror(); +#if USE_RGENGC + if (objspace->rgengc.during_minor_gc) { + /* do full GC */ + garbage_collect(objspace, TRUE, TRUE, GPR_FLAG_NEWOBJ | GPR_FLAG_MAJOR_BY_NOFREE); } + else { + gc_heap_allocate_minimum_page(objspace, heap); + } +#else + gc_heap_allocate_minimum_page(objspace, heap); +#endif } } @@ -2870,11 +2896,11 @@ heap_pages_swept_slots = 0; total_limit_slot = objspace_total_slot(objspace); - heap_pages_min_free_slots = (size_t)(total_limit_slot * 0.30); + heap_pages_min_free_slots = (size_t)(total_limit_slot * GC_HEAP_FREE_SLOTS_MIN_RATIO); if (heap_pages_min_free_slots < gc_params.heap_free_slots) { heap_pages_min_free_slots = gc_params.heap_free_slots; } - heap_pages_max_free_slots = (size_t)(total_limit_slot * 0.80); + heap_pages_max_free_slots = (size_t)(total_limit_slot * GC_HEAP_FREE_SLOTS_MAX_RATIO); if (heap_pages_max_free_slots < gc_params.heap_init_slots) { heap_pages_max_free_slots = gc_params.heap_init_slots; } @@ -2959,22 +2985,51 @@ static void gc_after_sweep(rb_objspace_t *objspace) { - rb_heap_t *heap = heap_eden; + /* extend heap when space is not enough */ +#if USE_RGENGC + if (objspace->rgengc.during_minor_gc) { + if (heap_pages_swept_slots < heap_pages_min_free_slots) { + objspace->rgengc.need_major_gc = GPR_FLAG_MAJOR_BY_RESCAN; + } + } + else { + /* check slots for newobj */ + if (heap_pages_swept_slots < heap_pages_min_free_slots) { + /* do not have enough slots for new objects */ + heap_set_increment(objspace, heap_extend_pages(objspace)); + } + else if (gc_params.oldobject_limit_factor > 1) { + size_t old_object_count = objspace->rgengc.old_object_count; + size_t old_object_max = (size_t)(objspace->rgengc.old_object_limit * (1 - GC_HEAP_FREE_SLOTS_MIN_RATIO)); - rgengc_report(1, objspace, "after_gc_sweep: heap->total_slots: %d, heap->swept_slots: %d, min_free_slots: %d\n", - (int)heap->total_slots, (int)heap_pages_swept_slots, (int)heap_pages_min_free_slots); + if (old_object_count > old_object_max) { + /* not enough old object space */ + heap_set_increment(objspace, (old_object_count - old_object_max) / HEAP_OBJ_LIMIT + 1); + } + } - if (heap_pages_swept_slots < heap_pages_min_free_slots) { - heap_set_increment(objspace, (heap_pages_min_free_slots - heap_pages_swept_slots) / HEAP_OBJ_LIMIT); - heap_increment(objspace, heap); + /* setup old_object_limit & remembered_shady_object_limit */ + { + /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */ + size_t old_object_count = objspace->rgengc.old_object_count; + size_t old_limit_by_total_slots = (size_t)(objspace_total_slot(objspace) * (1 - GC_HEAP_FREE_SLOTS_MIN_RATIO)); + const double r = gc_params.oldobject_limit_factor; + size_t old_limit_by_old_num = (size_t)(old_object_count * r); -#if USE_RGENGC - if (objspace->rgengc.remembered_shady_object_count + objspace->rgengc.old_object_count > (heap_pages_length * HEAP_OBJ_LIMIT) / 2) { - /* if [old]+[remembered shady] > [all object count]/2, then do major GC */ - objspace->rgengc.need_major_gc = GPR_FLAG_MAJOR_BY_RESCAN; + objspace->rgengc.old_object_limit = + old_limit_by_total_slots > old_limit_by_old_num ? + old_limit_by_old_num : old_limit_by_total_slots; + + /* should we merge remembered shady object limit? */ + objspace->rgengc.remembered_shady_object_limit = (size_t)(objspace->rgengc.remembered_shady_object_count * r); } + } +#else + if (heap_pages_swept_slots < heap_pages_min_free_slots) { + /* do not have enough slots for new objects */ + heap_set_increment(objspace, heap_extend_pages(objspace)); + } #endif - } gc_prof_set_heap_info(objspace); @@ -3082,8 +3137,6 @@ } gc_heap_lazy_sweep(objspace, heap_eden); } - - gc_heap_prepare_minimum_pages(objspace, heap_eden); } /* Marking - Marking stack */ @@ -4524,12 +4577,6 @@ #endif gc_marks_body(objspace, TRUE); - { - /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */ - const double r = gc_params.oldobject_limit_factor; - objspace->rgengc.remembered_shady_object_limit = (size_t)(objspace->rgengc.remembered_shady_object_count * r); - objspace->rgengc.old_object_limit = (size_t)(objspace->rgengc.old_object_count * r); - } } else { /* minor GC */ gc_marks_body(objspace, FALSE); @@ -5047,6 +5094,8 @@ } gc_prof_timer_stop(objspace); + gc_heap_prepare_minimum_pages(objspace, heap_eden); + if (GC_NOTIFY) fprintf(stderr, "end garbage_collect()\n"); return TRUE; } @@ -5057,7 +5106,7 @@ if (dont_gc || during_gc) { if (!heap->freelist && !heap->free_pages) { if (!heap_increment(objspace, heap)) { - heap_set_increment(objspace, 0); + heap_set_increment(objspace, 1); heap_increment(objspace, heap); } }