Some size pools may not have any pages/slots, so total_slots is 0. This
causes a divide-by-zero in the calculation. This commit adds a special
case to catch the case when total_slots is 0 and returns the number of
pages for heap_init_slots.
If the size pool has no or few pages/slots, then min_free_slots will
be a very small number (or even 0). Then the heap won't be eligible to
grow, causing GC thrashing or infinite loops.
Size pools with no pages won't be swept so gc_sweep_finish_size_pool
will never be called on it, but gc_sweep_finish_size_pool must be called
to grow the size pool.
Depending on alignment, the last bitmap plane may not used. Then it will
appear as if all of the objects on that plane is unmarked, which will
cause a buffer overrun when we try to free the object. This commit
changes the loop to calculate the number of planes used
(bitmap_plane_count).
Having more size pools will allow us to allocate larger objects
through Variable Width Allocation.
I have attached some benchmark results below.
Discourse:
On Discourse, we don't see much change in response times. We do see
a small reduction in RSS.
Branch RSS: 377.8 MB
Master RSS: 396.3 MB
railsbench:
On railsbench, we don't see a big change in RPS or p99 performance.
We see a small increase in RSS.
Branch RPS: 815.38
Master RPS: 811.73
Branch p99: 1.69 ms
Master p99: 1.68 ms
Branch RSS: 90.6 MB
Master RSS: 89.4 MB
liquid:
We don't see a significant change in liquid performance.
Branch parse & render: 29.041 I/s
Master parse & render: 29.211 I/s
Object#autoload implements a custom per-thread "mutex" for blocking
threads waiting on autoloading a feature. This causes problems when used
with the fiber scheduler. We swap the implementation to use a Ruby mutex
which is fiber aware.
Since 4d8f76286b, we need to dereference
the includer field on iclasses, so we need to mark it to make sure
it's alive.
Sometimes during compaction we crash because the field is dangling,
though I have a hard time constructing such a situation. See
http://ci.rvm.jp/results/trunk@ruby-iga/3947725
While walking over the list of subclasses for `include` and friends, we
check whether the subclass is a garbage object. After the check, we
allocate objects which might trigger GC and make the subclass garbage,
even though before the allocation the subclass was not garbage. This is
a sort of time-of-check-time-of-use issue.
Fix this by saving the weak reference to a local variable, upgrading it
to a strong reference while we do the allocation. It makes the code look
slightly nicer even if it doesn't fix any runtime issues.