Stateless closure cache: unbounded memory growth when the declaring closure has a heap runtime cache (bind/call/traits)
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
调研方向
The report points to ZEND_DECLARE_LAMBDA_FUNCTION, EG(lambda_cache), and the heap runtime cache used for rebound closures; it does not name source files or tests. Start by tracing the stateless closure cache and compare its behavior for ordinary closures and closures rebound with Closure::bind(), Closure::bindTo(), or Closure::call(). Reproduce with the provided loop and memory measurement, then check that repeated calls no longer grow memory while the closure remains usable.
由索引模型根据 Issue 内容生成。
描述
Description
ZEND_DECLARE_LAMBDA_FUNCTION caches a stateless (static fn) closure in the declaring function's runtime cache and pushes it onto EG(lambda_cache), which is only released at shutdown. When the declaring function is a closure that gets a fresh ZEND_ACC_HEAP_RT_CACHE on every creation/call (rebinding to another scope via Closure::bind()/bindTo(), Closure::call(), or a closure in a trait method used by more than one class), every call misses the cache and pushes another closure, so memory grows linearly for the whole request. This hurts long-running workers (e.g. Macroable-style Closure::bind($macro, null, static::class)).
The following code:
<?php
class A {}
$outer = function () { return (static fn() => 1)(); };
$m = memory_get_usage();
for ($i = 0; $i < 100000; $i++) {
Closure::bind($outer, null, A::class)();
}
echo memory_get_usage() - $m, "\n";
Resulted in this output:
40243200
But I expected this output instead (as in PHP 8.5.12):
0
Trait variant, no explicit binding:
<?php
trait T {
public function m($k) {
$f = function () use ($k) { return (static fn($x) => $x + 1)($k); };
return $f();
}
}
class U1 { use T; }
class U2 { use T; }
(new U1)->m(0);
$u2 = new U2;
$m = memory_get_usage();
for ($i = 0; $i < 100000; $i++) { $u2->m($i); }
echo memory_get_usage() - $m, "\n";
8.6: 41843072, 8.5.12: 0.
$outer->bindTo(null, A::class)() and $outer->call($obj) grow the same way. The debug build reports no leak because EG(lambda_cache) is cleaned at shutdown. Introduced by f47cd216e95 (stateless closure cache). Reproduces with opcache off, on, and with tracing JIT.
PHP Version
PHP 8.6.1-dev (cli) (NTS DEBUG), PHP-8.6 @ dfc3219f341
Operating System
macOS (arm64)
- 主要语言
- C
- 星标
- 41.8k
- 派生
- 8.5k
- 平均合并
- 2 天 13 小时
- 30 天内合并 PR
- 145
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
php/php-src 的其他 Issue
-
ext/openssl: 8.2.31+/8.3.31+ fail to build against OpenSSL 1.0.2 (ASN1_STRING_get0_data in xp_ssl.c)未关闭
难度 2/5 1-3 小时 新手友好度 79/100
维护者通常 1 天内回复
-
Bug Status: Needs Triage
难度 2/5 1-3 小时 新手友好度 68/100
维护者通常 1 天内回复
-
SNMP accepts malformed remote ports可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 2/5 半天 新手友好度 62/100
维护者通常 1 天内回复
-
Bug Status: Needs Triage
难度 2/5 1-3 小时 新手友好度 64/100
维护者通常 1 天内回复
-
quoted_printable_encode() produces lines longer than 76 characters for bytes 0xF5 to 0xFF可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 78/100
-
not for AI lovers
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
-
Template: Bug
难度 2/5 1-3 小时 新手友好度 83/100
betaflight/betaflight#16014 ·
维护者通常 3 天内回复
-
难度 1/5 1 小时以内 新手友好度 75/100
ly05010419/MacNativeGames#2119 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100