<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/gc/default, branch master</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>Run FREEOBJ hook as separate step</title>
<updated>2026-06-03T21:06:14+00:00</updated>
<author>
<name>John Hawthorn</name>
<email>john@hawthorn.email</email>
</author>
<published>2026-03-17T03:13:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=739ec91d5a06395206b103d9d499a3ff9af62203'/>
<id>739ec91d5a06395206b103d9d499a3ff9af62203</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Ensure DTrace probes capture all GC marking events</title>
<updated>2026-06-01T18:00:17+00:00</updated>
<author>
<name>Kunshan Wang</name>
<email>wks1986@gmail.com</email>
</author>
<published>2026-06-01T07:11:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=cc2547595ebd13e48b08e4f86c1d1a5d16f43756'/>
<id>cc2547595ebd13e48b08e4f86c1d1a5d16f43756</id>
<content type='text'>
`gc_prof_mark_timer_start` and `gc_prof_mark_timer_stop` include DTrace
hooks for the `MARK_BEGIN` and `MARK_END` events, respectively.
Previously, those probes are only triggered in `gc_marks`.  However,
`gc_marks_continue` and `gc_rest` also contain marking activities, but
are not captured by the probes.

We move the invocation of `gc_prof_mark_timer_start` and
`gc_prof_mark_timer_stop` into `gc_marking_enter` and `gc_marking_exit`
to ensure all marking activities are captured by the probes.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
`gc_prof_mark_timer_start` and `gc_prof_mark_timer_stop` include DTrace
hooks for the `MARK_BEGIN` and `MARK_END` events, respectively.
Previously, those probes are only triggered in `gc_marks`.  However,
`gc_marks_continue` and `gc_rest` also contain marking activities, but
are not captured by the probes.

We move the invocation of `gc_prof_mark_timer_start` and
`gc_prof_mark_timer_stop` into `gc_marking_enter` and `gc_marking_exit`
to ensure all marking activities are captured by the probes.
</pre>
</div>
</content>
</entry>
<entry>
<title>Unify gc_counter_t on rbimpl_atomic_uint64_t</title>
<updated>2026-05-20T21:14:47+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-19T10:37:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=4c8f07275dd39e693bf6dd932a32f7528b24d4dd'/>
<id>4c8f07275dd39e693bf6dd932a32f7528b24d4dd</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Snapshot malloc counters at end of sweep</title>
<updated>2026-05-20T21:14:47+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-14T22:54:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=8b7c4342afafdf9523c37ec8e48f192a7e8df289'/>
<id>8b7c4342afafdf9523c37ec8e48f192a7e8df289</id>
<content type='text'>
Snapshotting at start of marking lets sweep-time frees count against the
next epoch, which roughly halves GC frequency on alloc-heavy workloads.
Move the snapshot to end of sweep so the next epoch starts from a clean
baseline.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Snapshotting at start of marking lets sweep-time frees count against the
next epoch, which roughly halves GC frequency on alloc-heavy workloads.
Move the snapshot to end of sweep so the next epoch starts from a clean
baseline.
</pre>
</div>
</content>
</entry>
<entry>
<title>Make sure we flush the cached count to update heap slots</title>
<updated>2026-05-20T21:14:47+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-14T11:13:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=ed882010ccf0979a3939af98e52f04f077858592'/>
<id>ed882010ccf0979a3939af98e52f04f077858592</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Better feature detection for malloc counter locks</title>
<updated>2026-05-20T21:14:47+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-14T10:12:12+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=cb3b126eee405b57bb47c64d39b0ba287d41287d'/>
<id>cb3b126eee405b57bb47c64d39b0ba287d41287d</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Reorder rb_gc_impl_stat to keep heap_live_slots accurate</title>
<updated>2026-05-20T21:14:47+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-11T14:30:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=8f7e07bb22e0fe57e089e7342e4b39f607330ccd'/>
<id>8f7e07bb22e0fe57e089e7342e4b39f607330ccd</id>
<content type='text'>
Several SETs in rb_gc_impl_stat may allocate a T_BIGNUM RVALUE when
the value exceeds FIXNUM_MAX

This is invisible on LP64 but trips on LLP64 Windows and ILP32 Linux
where FIXNUM_MAX ~= 1.07GB.

If those allocations happen *after* setting heap_live_slots then
stat[:heap_live_slots] reflects a stale snapshot, and tests that assert
on it fail.

This commit reorders everything so every potentially-allocating SET runs
first, and the slot counters are SET last.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Several SETs in rb_gc_impl_stat may allocate a T_BIGNUM RVALUE when
the value exceeds FIXNUM_MAX

This is invisible on LP64 but trips on LLP64 Windows and ILP32 Linux
where FIXNUM_MAX ~= 1.07GB.

If those allocations happen *after* setting heap_live_slots then
stat[:heap_live_slots] reflects a stale snapshot, and tests that assert
on it fail.

This commit reorders everything so every potentially-allocating SET runs
first, and the slot counters are SET last.
</pre>
</div>
</content>
</entry>
<entry>
<title>Expose monotonic malloc/free totals via GC.stat</title>
<updated>2026-05-20T21:14:47+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-08T21:39:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=672ef4326c7e33bff0551a1fece8cb814c034709'/>
<id>672ef4326c7e33bff0551a1fece8cb814c034709</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Use monotonic add/sub counters for malloc_increase</title>
<updated>2026-05-20T21:14:47+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-06T11:40:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=ec114e5701839ac5bb8a97f901333b865ff96c8a'/>
<id>ec114e5701839ac5bb8a97f901333b865ff96c8a</id>
<content type='text'>
Replace the single
objspace-&gt;malloc_counters.{increase,oldmalloc_increase} size_t fields
with pairs of monotonically-increasing counters. Snapshots of these
counters are taken at each GC, so that the live malloc_increase is computed as

    (malloc - malloc_at_last_gc) - (free - free_at_last_gc)

We update the baselines at each GC. Minor GC's update malloc and free
associated with young objects only (counters).

Major GC's update based on "oldcounters" as well.

The malloc/free counters are 64 bits wide which should provide ample
headroom for real world programs (&gt;500 years at 1Gb/sec allocation rate
XD). We use size_t on 64-bit and uint64_t on 32-bit, wrapped by a
gc_counter_t struct.

However, because updating a uint64_t is a multi-instruction
operation on 32 bit architectures we have to introduce a lock to the
malloc_counters struct to avoid racing.

We introduced 2 new macros MALLOC_COUNTERS_LOCK and
MALLOC_COUNTERS_UNLOCK that use `rb_nativethread_lock_t`.

The lock is initialized in rb_gc_impl_objspace_init and destroyed in
rb_gc_impl_objspace_free. We chose this because it mirrors existing
finalizer_lock pattern in wbcheck.

On 64 bit platforms aligned 64 bit loads are atomic, and writes are
already using RUBY_ATOMIC_SIZE_ADD so the locks are not needed and the
macros do nothing.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Replace the single
objspace-&gt;malloc_counters.{increase,oldmalloc_increase} size_t fields
with pairs of monotonically-increasing counters. Snapshots of these
counters are taken at each GC, so that the live malloc_increase is computed as

    (malloc - malloc_at_last_gc) - (free - free_at_last_gc)

We update the baselines at each GC. Minor GC's update malloc and free
associated with young objects only (counters).

Major GC's update based on "oldcounters" as well.

The malloc/free counters are 64 bits wide which should provide ample
headroom for real world programs (&gt;500 years at 1Gb/sec allocation rate
XD). We use size_t on 64-bit and uint64_t on 32-bit, wrapped by a
gc_counter_t struct.

However, because updating a uint64_t is a multi-instruction
operation on 32 bit architectures we have to introduce a lock to the
malloc_counters struct to avoid racing.

We introduced 2 new macros MALLOC_COUNTERS_LOCK and
MALLOC_COUNTERS_UNLOCK that use `rb_nativethread_lock_t`.

The lock is initialized in rb_gc_impl_objspace_init and destroyed in
rb_gc_impl_objspace_free. We chose this because it mirrors existing
finalizer_lock pattern in wbcheck.

On 64 bit platforms aligned 64 bit loads are atomic, and writes are
already using RUBY_ATOMIC_SIZE_ADD so the locks are not needed and the
macros do nothing.
</pre>
</div>
</content>
</entry>
<entry>
<title>Preserve usable slot size when RVALUE_OVERHEAD is non-zero</title>
<updated>2026-05-20T10:44:12+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-18T13:50:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=332315a46487e11a5712388e43ad65bd5f97b72b'/>
<id>332315a46487e11a5712388e43ad65bd5f97b72b</id>
<content type='text'>
We made a mistake calculating slot sizes during the heap slot sizes
refactor. Previously BASE_SLOT_SIZE included RVALUE_OVERHEAD, this was
lost during the refactor to use the SLOT macro.

The result of this was that when Ruby was compiled with -DRUBY_DEBUG it
was assumed that the last word of each slot was RVALUE_OVERHEAD. Because
this hadn't been taken into account at allocation time, all slots were
effectively one word shorter.

This PR adds RVALUE_OVERHEAD to the size calcualted in the SLOT macro
directly, so it will be added on to the physically allocated size at
allocation time.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
We made a mistake calculating slot sizes during the heap slot sizes
refactor. Previously BASE_SLOT_SIZE included RVALUE_OVERHEAD, this was
lost during the refactor to use the SLOT macro.

The result of this was that when Ruby was compiled with -DRUBY_DEBUG it
was assumed that the last word of each slot was RVALUE_OVERHEAD. Because
this hadn't been taken into account at allocation time, all slots were
effectively one word shorter.

This PR adds RVALUE_OVERHEAD to the size calcualted in the SLOT macro
directly, so it will be added on to the physically allocated size at
allocation time.
</pre>
</div>
</content>
</entry>
</feed>
