Static $__joinPoint keeps the first instance of every woven class alive
I maintainer di solito rispondono entro 1 giorno
Una pull request collegata è già stata integrata.
- #802 di @lisachenko — integrata
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 22/100
Direzione di ricerca
Start with the generated static $__joinPoint initialiser and AbstractMethodInvocation::$closureToCall, then read DynamicTraitAliasMethodInvocation::resolveOriginalMethod(), which uses the closure only to find the method. Reproduce the leak with the WeakReference snippet from the issue. Done means the first instance is collectable after gc_collect_cycles() without changing invocation results, and composer test:performance shows no regression. A linked pull request (#802) already exists, so check it before starting.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
What happens
Each intercepted instance method creates its joinpoint once, in a function-scoped static:
static $__joinPoint = InterceptorInjector::forMethod(
self::class, 'sum', [...],
$this->sumOriginalAlias(...), // captures $this of the first call
);
The first-class callable captures the object of the first call. It is stored in AbstractMethodInvocation::$closureToCall (protected readonly Closure) and never released, so that object can't be garbage-collected until the end of the request:
$a = new Calc(); $a->sum(1, 1); $wa = WeakReference::create($a); unset($a); gc_collect_cycles();
$b = new Calc(); $b->sum(1, 1); $wb = WeakReference::create($b); unset($b); gc_collect_cycles();
var_dump($wa->get() !== null, $wb->get() !== null); // true, false: the first instance is still alive
The cost is one object per intercepted method, plus whatever that object references: entities, request objects, large graphs. Destructors of those objects run late. This isn't specific to PHP 8.6; it was found while checking whether PFA could replace this callable. PFA can't: 8.6 has no placeholder for $this, which the PFA RFC lists as future scope.
Cause
DynamicTraitAliasMethodInvocation only uses the closure to find the method: resolveOriginalMethod() reads the scope class and name, then calls ReflectionMethod::invokeArgs() on the current instance. The captured $this is never used.
Proposed fix (options)
- Pass the alias name instead of a callable, for example
InterceptorInjector::forMethod(self::class, 'sum', [...], 'sumOriginalAlias'), and resolvenew ReflectionMethod(self::class, 'sumOriginalAlias')lazily. For inherited methods without an alias, resolve the prototype from the parent class. This needs a migration path for theforMethod()signature and for existing caches. - Smaller fix: unset the closure after
resolveOriginalMethod(). This needs$closureToCallto stop beingreadonlyfor dynamic invocations, and it only frees the instance after the first call reaches the original body. An around advice that never proceeds keeps it alive.
Option 1 also makes the generated code a bit smaller. Check it with composer test:performance, since this touches the hot path.
Part of #789.
- Lingua principale
- PHP
- Stelle
- 1.7k
- Fork
- 166
- Merge medio
- 1g 1h
- PR unite (30g)
- 42
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di goaop/framework
-
Enhancement Performance
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
I maintainer di solito rispondono entro 1 giorno
-
Enhancement Performance To Be Discussed
Difficoltà 5/5 Più di una settimana Idoneità per principianti 28/100
goaop/framework#814 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
`PREBUILT_CACHE` weaves and writes the cache when a class is missing from it (fails on read-only file systems)Forse già presa @lisachenko l’ha presa oggi. ApertaBug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Enhancement PHP-8.6
Difficoltà 3/5 1-2 giorni Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Enhancement PHP-8.6 To Be Discussed
Difficoltà 4/5 Più di una settimana Idoneità per principianti 8/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di goaop/framework
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
YunoHost-Apps/snappymail_ynh#205 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
ExpressionEngine/ExpressionEngine#5453 ·
I maintainer di solito rispondono entro 1 giorno
-
✨️ai-candidate effort: [XS] Made by AI module: user interface type: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
0. Needs triage bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
I maintainer di solito rispondono entro 1 giorno
-
Type: Enhancement Type: Support
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
google/site-kit-wp#14096 ·
I maintainer di solito rispondono entro 2 giorni