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