Static $__joinPoint keeps the first instance of every woven class alive
Maintainer thường phản hồi trong vòng 1 ngày
Một pull request liên quan đã được merge.
- #802 của @lisachenko — đã merge
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 22/100
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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.
- Ngôn ngữ chính
- PHP
- Star
- 1.7k
- Fork
- 166
- Merge trung bình
- 1 ngày 1 giờ
- Pull request đã merge (30 ngày)
- 38
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của goaop/framework
-
Enhancement
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
cache:warmup:opcache runs out of memory with the default memory_limit (128M) on larger applicationsĐang mởBug
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 55/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug To Be Discussed
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 28/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug
Độ khó 4/5 1-2 ngày Mức phù hợp với người mới 56/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 45/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của goaop/framework
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Include flows spanning the full report time windowCó thể đã có người làm @somethingwithproof đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
Cacti/plugin_flowview#306 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
priority:low type:bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
crazy-goat/workerman-bundle#1189 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Captured slideshow pass overwrites the route path, aborting compose with a rebind() TypeErrorĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Automattic/blocks-engine#5003 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
from-cloud mythic tracked
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 86/100
MythicalLTD/FeatherPanel#459 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày