[Bugfix] entity.cell_pos = (x, y) leaks exactly 1 allocator block per assignment #414
Labels
No labels
Alpha Release Requirement
Bugfix
Demo Target
Documentation
Major Feature
Minor Feature
priority:tier1-active
priority:tier2-foundation
priority:tier3-future
priority:tier4-deferred
Refactoring & Cleanup
system:animation
system:documentation
system:grid
system:input
system:performance
system:procgen
system:python-binding
system:rendering
system:ui-hierarchy
Tiny Feature
workflow:blocked
workflow:needs-benchmark
workflow:needs-documentation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
john/McRogueFace#414
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while calibrating the allocator gate for the #395 soak test, and verified independently.
Measured
build/mcrogueface --headless, 2000-iteration warmup,gc.collect()before and after, 20000 assignments:Exactly one
sys.getallocatedblocks()per assignment, perfectly linear. Readingcell_posis clean, and an equivalent float-property assignment (Frame.x) is clean, so it is specific to thecell_possetter —UIEntity::set_cell_pos,src/UIEntity.cpp. Values were varied across the run, so it is not a small-int / interned-tuple artefact.Why it matters
cell_posis the entity-movement API. A single entity moving once per frame at 60 fps leaks ~216 000 objects per hour; a scenario with fifty entities moving on a turn loop leaks proportionally faster. This is the shape that presents as "the process grows until it is killed" after a long unattended run, with nothing pointing at the cause.RSS will not show it early: one leaked object per call is roughly 300 KB over 5000 calls, which the allocator can satisfy from arenas it already holds. A previous reviewer on this repo demonstrated exactly that — a real ~320 KB leak sitting invisible under a 4096 KB RSS threshold.
sys.getallocatedblocks()sees it immediately.Not diagnosed further here
I measured it rather than root-caused it; the setter's conversion path (
PyPosition/sfVector2ihandling, and whatever it builds for the position-change notification) is where to look. Filed rather than fixed because it needs its own refcount audit of that path and belongs with a regression gate, not folded into a frame-barrier task.A gate in the style of
tests/integration/frame_lock_soak_test.pysection 4 is the right shape:getallocatedblocks()across N assignments, gated well under 1 block per call, with a clean control property alongside so the gate cannot pass by measuring nothing.Sibling: #413 (
mcrfpy.get_metrics()leaks 8 blocks per call). Related: #395.