Skip to content

fix(symfony): clear SkolemIriConverter state between requests via ResetInterface#7829

Open
gwini wants to merge 3 commits intoapi-platform:4.2from
gwini:fix/skolem-iri-converter-memory-leak
Open

fix(symfony): clear SkolemIriConverter state between requests via ResetInterface#7829
gwini wants to merge 3 commits intoapi-platform:4.2from
gwini:fix/skolem-iri-converter-memory-leak

Conversation

@gwini
Copy link

@gwini gwini commented Mar 8, 2026

Q A
Branch? 4.2
Tickets
License MIT
Doc PR

SkolemIriConverter uses SplObjectStorage $objectHashMap and array $classHashMap to cache IRI mappings for non-entity objects during serialization. In long-running processes (FrankenPHP worker mode,
Swoole, RoadRunner), these maps accumulate entries across requests and are never cleared, causing a memory leak.

How I found it

Running Symfony 7.4 with API Platform 4.2.20 in FrankenPHP worker mode, I observed ~2.7 MB/request memory growth when calling an endpoint that serializes ~665 DTO objects (each containing two CarbonImmutable
properties). Memory grew linearly with every request and was never reclaimed by GC.

Using a deep object-graph scanner with reflection across all container services, I traced the leaked references to SkolemIriConverter::$objectHashMap — it held strong references to every serialized DTO and
its nested objects across all previous requests. The class never implements ResetInterface, so services_resetter never clears it.

After applying this fix, memory stabilized at ~76 MB across 20+ consecutive requests.

Changes

  • SkolemIriConverter now implements ResetInterface with a reset() method that clears both $objectHashMap and $classHashMap
  • The service is tagged with kernel.reset so Symfony automatically calls reset() between requests

Note: The Laravel variant (ApiPlatform\Laravel\Routing\SkolemIriConverter) has the same issue — its $objectHashMap and $classHashMap also grow unbounded across requests when running under Octane or other
long-running setups. I'm not familiar enough with Laravel's service lifecycle to implement the correct reset mechanism there. A follow-up PR for the Laravel side would be appreciated.

@gwini gwini marked this pull request as draft March 8, 2026 15:48
@gwini gwini changed the base branch from main to 4.2 March 8, 2026 15:49
@gwini gwini marked this pull request as ready for review March 8, 2026 15:49
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.

1 participant