Skip to content

Commit e53a6da

Browse files
Move all processing to postponed job.
1 parent 530ee76 commit e53a6da

File tree

7 files changed

+395
-198
lines changed

7 files changed

+395
-198
lines changed

ext/memory/profiler/allocations.c

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,70 +10,60 @@
1010

1111
static VALUE Memory_Profiler_Allocations = Qnil;
1212

13-
// Helper to mark object_states table values
14-
static int Memory_Profiler_Allocations_object_states_mark(st_data_t key, st_data_t value, st_data_t arg) {
15-
// Don't mark the object, we use it as a key but we never use it as an object, and we don't want to retain it.
16-
// VALUE object = (VALUE)key;
17-
// rb_gc_mark_movable(object);
18-
13+
// Helper to mark states table (object => state)
14+
static int Memory_Profiler_Allocations_states_mark(st_data_t key, st_data_t value, st_data_t arg) {
15+
// Don't mark the object key (weak reference - don't keep objects alive)
16+
// Mark the state value
1917
VALUE state = (VALUE)value;
20-
if (!NIL_P(state)) {
21-
rb_gc_mark_movable(state);
22-
}
18+
rb_gc_mark_movable(state);
2319
return ST_CONTINUE;
2420
}
2521

2622
// Foreach callback for st_foreach_with_replace (iteration logic)
27-
static int Memory_Profiler_Allocations_object_states_foreach(st_data_t key, st_data_t value, st_data_t argp, int error) {
23+
static int Memory_Profiler_Allocations_states_foreach(st_data_t key, st_data_t value, st_data_t argp, int error) {
2824
// Return ST_REPLACE to trigger the replace callback for each entry
2925
return ST_REPLACE;
3026
}
3127

32-
// Replace callback for st_foreach_with_replace to update object_states keys and values during compaction
33-
static int Memory_Profiler_Allocations_object_states_compact(st_data_t *key, st_data_t *value, st_data_t data, int existing) {
34-
VALUE old_object = (VALUE)*key;
28+
// Replace callback for st_foreach_with_replace to update states during compaction
29+
static int Memory_Profiler_Allocations_states_compact(st_data_t *key, st_data_t *value, st_data_t data, int existing) {
30+
// Key is object (VALUE) - we can't update if it moved (would require rehashing/allocation)
3531
VALUE old_state = (VALUE)*value;
36-
37-
VALUE new_object = rb_gc_location(old_object);
3832
VALUE new_state = rb_gc_location(old_state);
3933

40-
// Update key if it moved
41-
if (old_object != new_object) {
42-
*key = (st_data_t)new_object;
43-
}
34+
// NOTE: We can't update object keys if they moved (would require rehashing/allocation).
35+
// This means lookups may fail after compaction for moved objects.
36+
// This is acceptable - FREEOBJ will simply not find the state and skip the callback.
37+
// The state will be cleaned up when Allocations is freed/cleared.
4438

45-
// Update value if it moved
39+
// Update state value if it moved (this is safe, doesn't rehash)
4640
if (old_state != new_state) {
4741
*value = (st_data_t)new_state;
4842
}
4943

5044
return ST_CONTINUE;
5145
}
5246

53-
// GC mark function for Allocations
5447
static void Memory_Profiler_Allocations_mark(void *ptr) {
5548
struct Memory_Profiler_Capture_Allocations *record = ptr;
5649

5750
if (!record) {
5851
return;
5952
}
6053

61-
if (!NIL_P(record->callback)) {
62-
rb_gc_mark_movable(record->callback);
63-
}
54+
rb_gc_mark_movable(record->callback);
6455

65-
// Mark object_states table if it exists
66-
if (record->object_states) {
67-
st_foreach(record->object_states, Memory_Profiler_Allocations_object_states_mark, 0);
56+
// Mark states table if it exists
57+
if (record->states) {
58+
st_foreach(record->states, Memory_Profiler_Allocations_states_mark, 0);
6859
}
6960
}
7061

71-
// GC free function for Allocations
7262
static void Memory_Profiler_Allocations_free(void *ptr) {
7363
struct Memory_Profiler_Capture_Allocations *record = ptr;
7464

75-
if (record->object_states) {
76-
st_free_table(record->object_states);
65+
if (record->states) {
66+
st_free_table(record->states);
7767
}
7868

7969
xfree(record);
@@ -84,14 +74,12 @@ static void Memory_Profiler_Allocations_compact(void *ptr) {
8474
struct Memory_Profiler_Capture_Allocations *record = ptr;
8575

8676
// Update callback if it moved
87-
if (!NIL_P(record->callback)) {
88-
record->callback = rb_gc_location(record->callback);
89-
}
77+
record->callback = rb_gc_location(record->callback);
9078

91-
// Update object_states table if it exists
92-
if (record->object_states && record->object_states->num_entries > 0) {
93-
if (st_foreach_with_replace(record->object_states, Memory_Profiler_Allocations_object_states_foreach, Memory_Profiler_Allocations_object_states_compact, 0)) {
94-
rb_raise(rb_eRuntimeError, "object_states modified during GC compaction");
79+
// Update states table if it exists
80+
if (record->states && record->states->num_entries > 0) {
81+
if (st_foreach_with_replace(record->states, Memory_Profiler_Allocations_states_foreach, Memory_Profiler_Allocations_states_compact, 0)) {
82+
rb_raise(rb_eRuntimeError, "states modified during GC compaction");
9583
}
9684
}
9785
}
@@ -158,10 +146,11 @@ void Memory_Profiler_Allocations_clear(VALUE allocations) {
158146
record->free_count = 0; // Reset free count
159147
RB_OBJ_WRITE(allocations, &record->callback, Qnil); // Clear callback with write barrier
160148

161-
// Clear object states
162-
if (record->object_states) {
163-
st_free_table(record->object_states);
164-
record->object_states = NULL;
149+
// Clear states - either clear the table or reinitialize
150+
if (record->states) {
151+
st_clear(record->states);
152+
} else {
153+
record->states = st_init_numtable();
165154
}
166155
}
167156

ext/memory/profiler/allocations.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ struct Memory_Profiler_Capture_Allocations {
1717
size_t free_count;
1818
// Live count = new_count - free_count.
1919

20-
// For detailed tracking: map object (VALUE) => state (VALUE).
21-
// State is returned from callback on `newobj` and passed back on `freeobj`.
22-
st_table *object_states;
20+
// Map object (VALUE) => state (VALUE).
21+
// Object keys need compaction updates when they move.
22+
st_table *states;
2323
};
2424

2525
// Wrap an allocations record in a VALUE.

0 commit comments

Comments
 (0)