Static $__joinPoint keeps the first instance of every woven class alive
メンテナーはふだん 1 日以内に返信
関連するプルリクエストがすでにマージされています。
- #802 @lisachenko による — マージ済み
評価
調査の方向性
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.
索引モデルが issue の本文から書いたものです。
説明
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.
- 主要言語
- PHP
- スター
- 1.7k
- フォーク
- 166
- 平均マージ
- 1日 1時間
- マージ済み PR(30日)
- 43
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
goaop/framework のほかの issue
-
Bug
難易度 4/5 1〜2日 初心者へのやさしさ 56/100
メンテナーはふだん 1 日以内に返信
-
Bug
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
メンテナーはふだん 1 日以内に返信
-
Enhancement Performance
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
メンテナーはふだん 1 日以内に返信
-
Enhancement Performance To Be Discussed
難易度 5/5 1週間以上 初心者へのやさしさ 28/100
goaop/framework#814 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Enhancement PHP-8.6
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
goaop/framework の issue をすべて見る
似ている issue
-
sync-en
難易度 1/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
feature-request-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
Codeinwp/wp-menu-icons#360 ·
-
[Type] Bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 5 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
Automattic/blocks-engine#4874 ·
メンテナーはふだん 1 日以内に返信
-
Visual COBOL: missing 11.0 and 12.0, and 9.0 date differs from Rocket Software's lifecycle pageオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
endoflife-date/endoflife.date#11561 ·
メンテナーはふだん 1 日以内に返信