memory-profiler 1.1.13 → 1.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2cc3a03e3b76e232615954217c88c54d2077da267793f79c9b5dc5d8463398f6
4
- data.tar.gz: 29466a48c28857d7093156c80072dc3cba66420275b307cb2fea64102ece2624
3
+ metadata.gz: c26d5bc8b4215de3776e42ec9cd8daaf54a3cba9d55449f6b570ba7ee5ef9c91
4
+ data.tar.gz: 6668320402b35e3633eff016bd79b34c6b69952cb03120fc7f04886782bacfe3
5
5
  SHA512:
6
- metadata.gz: 9171990674d31df2af4daa7ed082b696ce1a093cb8f83ba6bab1d82ed1ef2704bb3cb4aef48758db7ba6b815e8729483d8b2124f3f687a77f3029400e1e3bb7b
7
- data.tar.gz: 4f4845133c13fe67caa4641df912280983d05f4c6e0fca324b0827f0ffbbd040710670e9d3cd1ef6e6ab7d61bbbe22334f89ffbf4286652f4d4e361891f2dfb5
6
+ metadata.gz: 68404ae44a442584084727cc854ed81abc36964c5621b93361cde70c6ae80f71ad21c7a45caf049c5906846cec8dff23ccbddb2e021eedf137e8ba7d57c78363
7
+ data.tar.gz: 406d8caac175e30907d752cec211d066a8c7ed5bf260c4e4eba6304f73b60d7c47be6d68d8b6cc4e738cb8fe19ebadeea0f251c7b2df888923b86abdaae2867e
checksums.yaml.gz.sig CHANGED
Binary file
@@ -138,9 +138,9 @@ const char *event_flag_name(rb_event_flag_t event_flag) {
138
138
  }
139
139
 
140
140
  // Process a NEWOBJ event. All allocation tracking logic is here.
141
- static void Memory_Profiler_Capture_process_newobj(VALUE capture_value, VALUE klass, VALUE object) {
141
+ static void Memory_Profiler_Capture_process_newobj(VALUE self, VALUE klass, VALUE object) {
142
142
  struct Memory_Profiler_Capture *capture;
143
- TypedData_Get_Struct(capture_value, struct Memory_Profiler_Capture, &Memory_Profiler_Capture_type, capture);
143
+ TypedData_Get_Struct(self, struct Memory_Profiler_Capture, &Memory_Profiler_Capture_type, capture);
144
144
 
145
145
  // Pause the capture to prevent infinite loop:
146
146
  capture->paused += 1;
@@ -168,8 +168,8 @@ static void Memory_Profiler_Capture_process_newobj(VALUE capture_value, VALUE kl
168
168
 
169
169
  allocations = Memory_Profiler_Allocations_wrap(record);
170
170
  st_insert(capture->tracked_classes, (st_data_t)klass, (st_data_t)allocations);
171
- RB_OBJ_WRITTEN(capture_value, Qnil, klass);
172
- RB_OBJ_WRITTEN(capture_value, Qnil, allocations);
171
+ RB_OBJ_WRITTEN(self, Qnil, klass);
172
+ RB_OBJ_WRITTEN(self, Qnil, allocations);
173
173
  }
174
174
 
175
175
  // Only store state if there's a callback
@@ -298,6 +298,29 @@ static void Memory_Profiler_Capture_event_callback(VALUE data, void *ptr) {
298
298
  VALUE klass = rb_class_of(object);
299
299
  if (!klass) return;
300
300
 
301
+ // Check if class is already freed (T_NONE). This can happen when:
302
+ // 1. Object was allocated before capture started (no NEWOBJ event queued).
303
+ // 2. Anonymous class (Class.new) was freed before its instances.
304
+ //
305
+ // If the class is T_NONE, it means:
306
+ // - It's NOT in tracked_classes (would retain it via GC mark callback).
307
+ // - It's NOT in any pending NEWOBJ event (would retain it via event queue marking).
308
+ //
309
+ // Therefore process_freeobj() would skip this event anyway (class lookup fails at line 200).
310
+ // We must skip enqueueing to avoid attempting to mark a T_NONE object during GC,
311
+ // which can cause: [BUG] try to mark T_NONE object.
312
+ if (rb_type(klass) == T_NONE) {
313
+ return;
314
+ }
315
+
316
+ if (DEBUG) {
317
+ const char *klass_name = "(ignored)";
318
+ if (event_flag == RUBY_INTERNAL_EVENT_NEWOBJ) {
319
+ klass_name = rb_class2name(klass);
320
+ }
321
+ fprintf(stderr, "Memory_Profiler_Capture_event_callback: object=%p, event_flag=%s, klass=%s\n", (void*)object, event_flag_name(event_flag), klass_name);
322
+ }
323
+
301
324
  if (event_flag == RUBY_INTERNAL_EVENT_NEWOBJ) {
302
325
  // Skip NEWOBJ if disabled (during callback) to prevent infinite recursion
303
326
  if (capture->paused) return;
@@ -417,7 +440,7 @@ static VALUE Memory_Profiler_Capture_track(int argc, VALUE *argv, VALUE self) {
417
440
  RB_OBJ_WRITE(self, &record->callback, callback);
418
441
  } else {
419
442
  struct Memory_Profiler_Capture_Allocations *record = ALLOC(struct Memory_Profiler_Capture_Allocations);
420
- record->callback = callback; // Initial assignment, no write barrier needed
443
+ RB_OBJ_WRITE(self, &record->callback, callback);
421
444
  record->new_count = 0;
422
445
  record->free_count = 0;
423
446
  record->states = st_init_numtable();
@@ -426,14 +449,8 @@ static VALUE Memory_Profiler_Capture_track(int argc, VALUE *argv, VALUE self) {
426
449
  allocations = Memory_Profiler_Allocations_wrap(record);
427
450
 
428
451
  st_insert(capture->tracked_classes, (st_data_t)klass, (st_data_t)allocations);
429
- // Notify GC about the class VALUE stored as key in the table
430
452
  RB_OBJ_WRITTEN(self, Qnil, klass);
431
- // Notify GC about the allocations VALUE stored as value in the table
432
453
  RB_OBJ_WRITTEN(self, Qnil, allocations);
433
- // Now inform GC about the callback reference
434
- if (!NIL_P(callback)) {
435
- RB_OBJ_WRITTEN(self, Qnil, callback);
436
- }
437
454
  }
438
455
 
439
456
  return allocations;
@@ -31,6 +31,7 @@ static void Memory_Profiler_Events_mark(void *ptr);
31
31
  static void Memory_Profiler_Events_compact(void *ptr);
32
32
  static void Memory_Profiler_Events_free(void *ptr);
33
33
  static size_t Memory_Profiler_Events_memsize(const void *ptr);
34
+ static const char *Memory_Profiler_Event_Type_name(enum Memory_Profiler_Event_Type type);
34
35
 
35
36
  // TypedData definition for Events.
36
37
  static const rb_data_type_t Memory_Profiler_Events_type = {
@@ -102,15 +103,9 @@ static void Memory_Profiler_Events_mark_queue(struct Memory_Profiler_Queue *queu
102
103
  // Skip already-processed events if requested:
103
104
  if (skip_none && event->type == MEMORY_PROFILER_EVENT_TYPE_NONE) continue;
104
105
 
105
- // Mark the Capture instance and class:
106
106
  rb_gc_mark_movable(event->capture);
107
107
  rb_gc_mark_movable(event->klass);
108
-
109
- // For NEWOBJ: mark the object to keep it alive until processor runs
110
- // For FREEOBJ: DON'T mark (object is being freed)
111
- if (event->type == MEMORY_PROFILER_EVENT_TYPE_NEWOBJ) {
112
- rb_gc_mark_movable(event->object);
113
- }
108
+ rb_gc_mark_movable(event->object);
114
109
  }
115
110
  }
116
111
 
@@ -133,7 +128,6 @@ static void Memory_Profiler_Events_compact_queue(struct Memory_Profiler_Queue *q
133
128
  // Skip already-processed events if requested:
134
129
  if (skip_none && event->type == MEMORY_PROFILER_EVENT_TYPE_NONE) continue;
135
130
 
136
- // Update all VALUEs if they moved during compaction:
137
131
  event->capture = rb_gc_location(event->capture);
138
132
  event->klass = rb_gc_location(event->klass);
139
133
  event->object = rb_gc_location(event->object);
@@ -7,7 +7,7 @@
7
7
  module Memory
8
8
  # @namespace
9
9
  module Profiler
10
- VERSION = "1.1.13"
10
+ VERSION = "1.1.14"
11
11
  end
12
12
  end
13
13
 
data/readme.md CHANGED
@@ -22,6 +22,10 @@ Please see the [project documentation](https://socketry.github.io/memory-profile
22
22
 
23
23
  Please see the [project releases](https://socketry.github.io/memory-profiler/releases/index) for all releases.
24
24
 
25
+ ### v1.1.14
26
+
27
+ - Ignore `freeobj` events for objects with anonymous classes that are not tracked (and thus become `T_NONE`).
28
+
25
29
  ### v1.1.13
26
30
 
27
31
  - Fix sampler loop interval handling.
@@ -66,10 +70,6 @@ Please see the [project releases](https://socketry.github.io/memory-profiler/rel
66
70
 
67
71
  - Use queue for `newobj` too to avoid invoking user code during object allocation.
68
72
 
69
- ### v1.1.2
70
-
71
- - Fix handling of GC compaction (I hope).
72
-
73
73
  ## Contributing
74
74
 
75
75
  We welcome contributions to this project.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v1.1.14
4
+
5
+ - Ignore `freeobj` events for objects with anonymous classes that are not tracked (and thus become `T_NONE`).
6
+
3
7
  ## v1.1.13
4
8
 
5
9
  - Fix sampler loop interval handling.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memory-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.13
4
+ version: 1.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file