mirror of
https://github.com/ruby/ruby.git
synced 2026-10-29 17:06:21 +08:00
Fix malloc counters during GC
https://github.com/ruby/ruby/pull/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}
This commit is contained in:
1 parent
e16d406db2
commit
45fd5d58f1
1 file changed
+3
-7
Notes:
git
2026-09-14 01:47:40 +00:00
@@ -4212,13 +4212,6 @@ gc_sweep_finish(rb_objspace_t *objspace)
|
||||
}
|
||||
}
|
||||
|
||||
gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.counters);
|
||||
#if RGENGC_ESTIMATE_OLDMALLOC
|
||||
if (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) {
|
||||
gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.oldcounters);
|
||||
}
|
||||
#endif
|
||||
|
||||
rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP);
|
||||
gc_mode_transition(objspace, gc_mode_none);
|
||||
|
||||
@@ -6669,6 +6662,7 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
|
||||
gc_prof_set_malloc_info(objspace);
|
||||
{
|
||||
int64_t inc = gc_malloc_counters_increase(objspace, &objspace->malloc_counters.counters);
|
||||
gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.counters);
|
||||
size_t old_limit = malloc_limit;
|
||||
|
||||
/* A net-negative `inc` (more freed than malloc'd since last GC) is
|
||||
@@ -6724,6 +6718,8 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
|
||||
gc_params.oldmalloc_limit_max);
|
||||
}
|
||||
else {
|
||||
gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.oldcounters);
|
||||
|
||||
if ((objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_BY_OLDMALLOC) == 0) {
|
||||
objspace->rgengc.oldmalloc_increase_limit =
|
||||
(size_t)(objspace->rgengc.oldmalloc_increase_limit / ((gc_params.oldmalloc_limit_growth_factor - 1)/10 + 1));
|
||||
|
||||
Reference in new issue
Block a user