Skip to content

fix(serializer): avoid creating reference cycles on every call#6563

Merged
alexander-alderman-webb merged 1 commit into
getsentry:masterfrom
Malkiz223:fix/serializer-reference-cycles
Jun 12, 2026
Merged

fix(serializer): avoid creating reference cycles on every call#6563
alexander-alderman-webb merged 1 commit into
getsentry:masterfrom
Malkiz223:fix/serializer-reference-cycles

Conversation

@Malkiz223

Copy link
Copy Markdown
Contributor

Description

serialize() used to define eight nested functions referencing each other through closure cells, so every call left a reference cycle behind. Only the cyclic GC can free such cycles, so applications running with gc.disable() leak memory on every captured event, and everyone else pays collector pressure on the error path. On Python 3.14 the cycle is even bigger: PEP 649 adds a hidden __annotate__ function per nested function, and those get caught in it too.

As discussed in #6559: the helpers are moved as-is onto a private per-call class _Serializer, and serialize() creates an instance of it. The public serialize() and its signature are unchanged, the helper logic is untouched, so behaviour stays identical. Everything a call creates is now freed by plain reference counting.

There is no performance cost. In an interleaved microbenchmark (medians of 9 rounds, small/medium/frame-vars sample events) the class version performs the same as the nested functions on Python 3.12. On Python 3.14 small events serialize ~1.5x faster (9.0 -> 5.7 us/call here), since a call no longer creates eight closures plus their PEP 649 __annotate__ functions.

Also adds a regression test asserting that serialize() leaves no cyclic garbage behind (checked under gc.DEBUG_SAVEALL with the GC disabled).

Issues

@Malkiz223 Malkiz223 marked this pull request as ready for review June 12, 2026 11:00
@Malkiz223 Malkiz223 requested a review from a team as a code owner June 12, 2026 11:00
@alexander-alderman-webb alexander-alderman-webb enabled auto-merge (squash) June 12, 2026 13:12
@alexander-alderman-webb alexander-alderman-webb merged commit 62af515 into getsentry:master Jun 12, 2026
139 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory leak: serializer.serialize() creates reference cycles on every call

2 participants