Skip to content

Commit c5ca470

Browse files
peterzhu2118luke-gruber
authored andcommitted
Fix malloc counters during GC
ruby#16919 changed malloc counters to be reset in `gc_sweep_finish`. However, this introduced two problems: 1. If a GC is triggered due to the `malloc_limit` being hit, then it would run a GC with lazy sweeping, during lazy sweeping Ruby code could call `xmalloc`, which would immediately finish sweeping by calling `gc_rest` because the `malloc_increase` is not reset. 2. When `gc_rest` is called, it immediately completes sweeping. However, all of the counters for the freed memory is lost because `malloc_increase` is reset at the end. Previously, lazy sweeping would be interleaved with Ruby code execution, meaning `xfree` was interleaved with `xmalloc`, allowing for more memory to be allocated before `malloc_increase` hits `malloc_limit`. The issue can be reproduced by this script: live = [] 500.times do live << Array.new(200) { String.new(capacity: 64 * 1024) } end puts GC.stat Before: {count: 235, ..., minor_gc_count: 196, major_gc_count: 39} After: {count: 196, ..., minor_gc_count: 153, major_gc_count: 43}
1 parent ad06e4a commit c5ca470

1 file changed

Lines changed: 3 additions & 7 deletions

File tree

gc/default/default.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4023,13 +4023,6 @@ gc_sweep_finish(rb_objspace_t *objspace)
40234023
}
40244024
}
40254025

4026-
(void)gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.counters);
4027-
#if RGENGC_ESTIMATE_OLDMALLOC
4028-
if (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) {
4029-
(void)gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.oldcounters);
4030-
}
4031-
#endif
4032-
40334026
rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP);
40344027
gc_mode_transition(objspace, gc_mode_none);
40354028

@@ -6464,6 +6457,7 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
64646457
gc_prof_set_malloc_info(objspace);
64656458
{
64666459
int64_t inc = gc_malloc_counters_increase(objspace, &objspace->malloc_counters.counters);
6460+
gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.counters);
64676461
size_t old_limit = malloc_limit;
64686462

64696463
/* A net-negative `inc` (more freed than malloc'd since last GC) is
@@ -6519,6 +6513,8 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
65196513
gc_params.oldmalloc_limit_max);
65206514
}
65216515
else {
6516+
gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.oldcounters);
6517+
65226518
if ((objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_BY_OLDMALLOC) == 0) {
65236519
objspace->rgengc.oldmalloc_increase_limit =
65246520
(size_t)(objspace->rgengc.oldmalloc_increase_limit / ((gc_params.oldmalloc_limit_growth_factor - 1)/10 + 1));

0 commit comments

Comments
 (0)