@@ -18,36 +18,34 @@ enum {
1818
1919static VALUE Memory_Profiler_Capture = Qnil ;
2020
21- // Event symbols
22- static VALUE sym_newobj ;
23- static VALUE sym_freeobj ;
21+ // Event symbols:
22+ static VALUE sym_newobj , sym_freeobj ;
2423
25- // Main capture state (per-instance)
24+ // Main capture state (per-instance).
2625struct Memory_Profiler_Capture {
27- // class => VALUE (wrapped Memory_Profiler_Capture_Allocations).
26+ // Tracked classes: class => VALUE (wrapped Memory_Profiler_Capture_Allocations).
2827 st_table * tracked_classes ;
2928
30- // Master switch - is tracking active? (set by start/stop)
29+ // Master switch - is tracking active? (set by start/stop).
3130 int running ;
3231
33- // Internal - should we queue callbacks? (temporarily disabled during queue processing)
32+ // Should we queue callbacks? (temporarily disabled during queue processing).
3433 int enabled ;
3534};
3635
37- // GC mark callback for tracked_classes table
36+ // GC mark callback for tracked_classes table.
3837static int Memory_Profiler_Capture_tracked_classes_mark (st_data_t key , st_data_t value , st_data_t arg ) {
39- // Mark class as un-movable as we don't want it moving in freeobj.
38+ // Mark class as un-movable:
4039 VALUE klass = (VALUE )key ;
4140 rb_gc_mark (klass );
4241
43- // Mark the wrapped Allocations VALUE (its own mark function will handle internal refs)
42+ // Mark the wrapped Allocations VALUE:
4443 VALUE allocations = (VALUE )value ;
4544 rb_gc_mark_movable (allocations );
4645
4746 return ST_CONTINUE ;
4847}
4948
50- // GC mark function
5149static void Memory_Profiler_Capture_mark (void * ptr ) {
5250 struct Memory_Profiler_Capture * capture = ptr ;
5351
@@ -56,7 +54,6 @@ static void Memory_Profiler_Capture_mark(void *ptr) {
5654 }
5755}
5856
59- // GC free function
6057static void Memory_Profiler_Capture_free (void * ptr ) {
6158 struct Memory_Profiler_Capture * capture = ptr ;
6259
@@ -67,7 +64,6 @@ static void Memory_Profiler_Capture_free(void *ptr) {
6764 xfree (capture );
6865}
6966
70- // GC memsize function
7167static size_t Memory_Profiler_Capture_memsize (const void * ptr ) {
7268 const struct Memory_Profiler_Capture * capture = ptr ;
7369 size_t size = sizeof (struct Memory_Profiler_Capture );
@@ -79,22 +75,21 @@ static size_t Memory_Profiler_Capture_memsize(const void *ptr) {
7975 return size ;
8076}
8177
82- // Foreach callback for st_foreach_with_replace (iteration logic)
78+ // Foreach callback for st_foreach_with_replace (iteration logic).
8379static int Memory_Profiler_Capture_tracked_classes_foreach (st_data_t key , st_data_t value , st_data_t argp , int error ) {
84- // Return ST_REPLACE to trigger the replace callback for each entry
8580 return ST_REPLACE ;
8681}
8782
88- // Replace callback for st_foreach_with_replace (update logic)
83+ // Replace callback for st_foreach_with_replace (update logic).
8984static int Memory_Profiler_Capture_tracked_classes_update (st_data_t * key , st_data_t * value , st_data_t argp , int existing ) {
90- // Update class key if it moved
85+ // Update class key if it moved:
9186 VALUE old_klass = (VALUE )* key ;
9287 VALUE new_klass = rb_gc_location (old_klass );
9388 if (old_klass != new_klass ) {
9489 * key = (st_data_t )new_klass ;
9590 }
9691
97- // Update wrapped Allocations VALUE if it moved (its own compact function handles internal refs)
92+ // Update wrapped Allocations VALUE if it moved:
9893 VALUE old_allocations = (VALUE )* value ;
9994 VALUE new_allocations = rb_gc_location (old_allocations );
10095 if (old_allocations != new_allocations ) {
@@ -104,18 +99,15 @@ static int Memory_Profiler_Capture_tracked_classes_update(st_data_t *key, st_dat
10499 return ST_CONTINUE ;
105100}
106101
107- // GC compact function
108102static void Memory_Profiler_Capture_compact (void * ptr ) {
109103 struct Memory_Profiler_Capture * capture = ptr ;
110104
111- // Update tracked_classes keys and allocations values in-place
105+ // Update tracked_classes keys and allocations values in-place:
112106 if (capture -> tracked_classes && capture -> tracked_classes -> num_entries > 0 ) {
113107 if (st_foreach_with_replace (capture -> tracked_classes , Memory_Profiler_Capture_tracked_classes_foreach , Memory_Profiler_Capture_tracked_classes_update , 0 )) {
114108 rb_raise (rb_eRuntimeError , "tracked_classes modified during GC compaction" );
115109 }
116110 }
117-
118- // Global event queue is automatically compacted via its pinned TypedData object
119111}
120112
121113static const rb_data_type_t Memory_Profiler_Capture_type = {
@@ -147,24 +139,22 @@ const char *event_flag_name(rb_event_flag_t event_flag) {
147139 }
148140}
149141
150- // Internal: Process a NEWOBJ event
151- // Handles both callback and non-callback cases, stores appropriate state
142+ // Process a NEWOBJ event. Handles both callback and non-callback cases, stores appropriate state.
152143static void Memory_Profiler_Capture_process_newobj (VALUE capture_value , VALUE klass , VALUE allocations , VALUE object ) {
153144 struct Memory_Profiler_Capture * capture ;
154145 TypedData_Get_Struct (capture_value , struct Memory_Profiler_Capture , & Memory_Profiler_Capture_type , capture );
155146
156147 struct Memory_Profiler_Capture_Allocations * record = Memory_Profiler_Allocations_get (allocations );
157148
158- // Ensure object_states table exists
149+ // Ensure object_states table exists:
159150 if (!record -> object_states ) {
160151 record -> object_states = st_init_numtable ();
161152 }
162153
163154 VALUE state ;
164155
165156 if (!NIL_P (record -> callback )) {
166- // Call callback and store returned state
167- // Temporarily disable queueing to prevent infinite loop if callback allocates
157+ // Temporarily disable queueing to prevent infinite loop:
168158 int was_enabled = capture -> enabled ;
169159 capture -> enabled = 0 ;
170160
@@ -174,38 +164,35 @@ static void Memory_Profiler_Capture_process_newobj(VALUE capture_value, VALUE kl
174164
175165 if (DEBUG_STATE ) fprintf (stderr , "Storing callback state for object: %p\n" , (void * )object );
176166 } else {
177- // No callback: store sentinel
178- // Qnil = "tracked but no callback data"
167+ // No callback, store sentinel (Qnil):
179168 state = Qnil ;
180169
181170 if (DEBUG_STATE ) fprintf (stderr , "Storing sentinel (Qnil) for object: %p\n" , (void * )object );
182171 }
183172
184- // Always store something to maintain NEWOBJ/FREEOBJ symmetry
173+ // Always store something to maintain NEWOBJ/FREEOBJ symmetry:
185174 st_insert (record -> object_states , (st_data_t )object , (st_data_t )state );
186175}
187176
188- // Internal: Process a FREEOBJ event
189- // Looks up and deletes state, optionally calls callback
177+ // Process a FREEOBJ event. Looks up and deletes state, optionally calls callback.
190178static void Memory_Profiler_Capture_process_freeobj (VALUE capture_value , VALUE klass , VALUE allocations , VALUE object ) {
191179 struct Memory_Profiler_Capture * capture ;
192180 TypedData_Get_Struct (capture_value , struct Memory_Profiler_Capture , & Memory_Profiler_Capture_type , capture );
193181
194182 struct Memory_Profiler_Capture_Allocations * record = Memory_Profiler_Allocations_get (allocations );
195183
196- // Try to look up and delete state
184+ // Try to look up and delete state:
197185 if (record -> object_states ) {
198186 st_data_t state_data ;
199187 if (st_delete (record -> object_states , (st_data_t * )& object , & state_data )) {
200188 VALUE state = (VALUE )state_data ;
201189
202- // Found state - object was allocated during our tracking session
203190 if (DEBUG_STATE ) fprintf (stderr , "Freed tracked object: %p, state=%s\n" ,
204191 (void * )object , NIL_P (state ) ? "Qnil (sentinel)" : "real state" );
205192
206- // Only call callback if we have both callback AND real state (not Qnil sentinel)
193+ // Only call callback if we have both callback AND real state (not Qnil sentinel):
207194 if (!NIL_P (record -> callback ) && !NIL_P (state )) {
208- // Temporarily disable queueing to prevent infinite loop if callback allocates
195+ // Temporarily disable queueing to prevent infinite loop:
209196 int was_enabled = capture -> enabled ;
210197 capture -> enabled = 0 ;
211198
@@ -214,14 +201,12 @@ static void Memory_Profiler_Capture_process_freeobj(VALUE capture_value, VALUE k
214201 capture -> enabled = was_enabled ;
215202 }
216203 } else {
217- // State not found - object allocated before tracking started
218204 if (DEBUG_STATE ) fprintf (stderr , "Freed pre-existing object: %p (not tracked)\n" , (void * )object );
219205 }
220206 }
221207}
222208
223- // Public API: Process a single event (NEWOBJ or FREEOBJ)
224- // Called from events.c via rb_protect to catch exceptions
209+ // Process a single event (NEWOBJ or FREEOBJ). Called from events.c via rb_protect to catch exceptions.
225210void Memory_Profiler_Capture_process_event (struct Memory_Profiler_Event * event ) {
226211 switch (event -> type ) {
227212 case MEMORY_PROFILER_EVENT_TYPE_NEWOBJ :
@@ -235,19 +220,18 @@ void Memory_Profiler_Capture_process_event(struct Memory_Profiler_Event *event)
235220
236221#pragma mark - Event Handlers
237222
238- // Handler for NEWOBJ event - increment count and enqueue
239- // Automatically tracks ALL allocations (creates records on demand)
223+ // NEWOBJ event handler. Automatically tracks ALL allocations (creates records on demand).
240224static void Memory_Profiler_Capture_newobj_handler (VALUE self , struct Memory_Profiler_Capture * capture , VALUE klass , VALUE object ) {
241225 st_data_t allocations_data ;
242226 VALUE allocations ;
243227
244228 if (st_lookup (capture -> tracked_classes , (st_data_t )klass , & allocations_data )) {
245- // Existing record - increment count
229+ // Existing record, increment count:
246230 allocations = (VALUE )allocations_data ;
247231 struct Memory_Profiler_Capture_Allocations * record = Memory_Profiler_Allocations_get (allocations );
248232 record -> new_count ++ ;
249233 } else {
250- // First time seeing this class - create record automatically
234+ // First time seeing this class, create record automatically:
251235 struct Memory_Profiler_Capture_Allocations * record = ALLOC (struct Memory_Profiler_Capture_Allocations );
252236 record -> callback = Qnil ;
253237 record -> new_count = 1 ;
@@ -260,28 +244,25 @@ static void Memory_Profiler_Capture_newobj_handler(VALUE self, struct Memory_Pro
260244 RB_OBJ_WRITTEN (self , Qnil , allocations );
261245 }
262246
263- // Enqueue to global event queue
247+ // Enqueue to global event queue:
264248 Memory_Profiler_Events_enqueue (MEMORY_PROFILER_EVENT_TYPE_NEWOBJ , self , klass , allocations , object );
265249}
266250
267- // Handler for FREEOBJ event - increment count and enqueue
268- // Simple: just count + enqueue, all logic is in queue processing
251+ // FREEOBJ event handler. Increments count and enqueues for processing.
269252static void Memory_Profiler_Capture_freeobj_handler (VALUE self , struct Memory_Profiler_Capture * capture , VALUE klass , VALUE object ) {
270253 st_data_t allocations_data ;
271254 if (st_lookup (capture -> tracked_classes , (st_data_t )klass , & allocations_data )) {
272255 VALUE allocations = (VALUE )allocations_data ;
273256 struct Memory_Profiler_Capture_Allocations * record = Memory_Profiler_Allocations_get (allocations );
274257
275- // Always track counts
276258 record -> free_count ++ ;
277259
278- // Enqueue to global event queue
260+ // Enqueue to global event queue:
279261 Memory_Profiler_Events_enqueue (MEMORY_PROFILER_EVENT_TYPE_FREEOBJ , self , klass , allocations , object );
280262 }
281263}
282264
283- // Check if object type is trackable (has valid class pointer and is a normal Ruby object)
284- // Excludes internal types (T_IMEMO, T_NODE, T_ICLASS, etc.) that don't have normal classes
265+ // Check if object type is trackable. Excludes internal types (T_IMEMO, T_NODE, T_ICLASS, etc.) that don't have normal classes.
285266int Memory_Profiler_Capture_trackable_p (VALUE object ) {
286267 switch (rb_type (object )) {
287268 // Normal Ruby objects with valid class pointers
0 commit comments