Bug #9607 » gc.patch
| gc.c (working copy) | ||
|---|---|---|
|
#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
|
||
| ... | ... | |
|
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
|
||
| ... | ... | |
|
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
|
||
|
}
|
||
|
}
|
||
|
|
||
| ... | ... | |
|
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;
|
||
|
}
|
||
| ... | ... | |
|
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);
|
||
|
|
||
| ... | ... | |
|
}
|
||
|
gc_heap_lazy_sweep(objspace, heap_eden);
|
||
|
}
|
||
|
|
||
|
gc_heap_prepare_minimum_pages(objspace, heap_eden);
|
||
|
}
|
||
|
|
||
|
/* Marking - Marking stack */
|
||
| ... | ... | |
|
#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);
|
||
| ... | ... | |
|
}
|
||
|
gc_prof_timer_stop(objspace);
|
||
|
|
||
|
gc_heap_prepare_minimum_pages(objspace, heap_eden);
|
||
|
|
||
|
if (GC_NOTIFY) fprintf(stderr, "end garbage_collect()\n");
|
||
|
return TRUE;
|
||
|
}
|
||
| ... | ... | |
|
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);
|
||
|
}
|
||
|
}
|
||