From 7b95e16bf8195cc612f010eeddf82298cf811971 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 24 Oct 2026 12:48:25 +0800 Subject: [PATCH] =?UTF-8?q?perf(memhub):=20=E6=B4=BB=E8=B7=83=E5=9D=97?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E6=94=B9=E4=B8=BA=E4=BB=85=20--detection=20?= =?UTF-8?q?=E7=94=9F=E6=95=88=EF=BC=8C=E6=B6=88=E9=99=A4=20free=20?= =?UTF-8?q?=E7=9A=84=20O(N)=20=E6=89=AB=E6=8F=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _is_valid_ptr 的 live-set 检查会对 chk_stack 线性扫描(长度 = chk_depth)。PermPool 永不 reset,窗口单调增长到数百万条,类型驻留开始归还缓冲后每次 free 都扫描整个窗口,使 PhaseA 单文件翻译退化到分钟级。该检查与 --detection 同级(诊断用),改为仅在检测模式执行;生产路径仍靠头部奇偶位拒绝重复 free,保持 O(1)。 --- memhub.vp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/memhub.vp b/memhub.vp index 5ebe64b..ca7105a 100644 --- a/memhub.vp +++ b/memhub.vp @@ -1444,12 +1444,15 @@ class MemBuddy(MemManager): order: int = int(stored_val >> 1) if order < 0: return 0 if order > self.max_order: return 0 - # Live-set check: every alloc pushes its block onto chk_stack, and reset_to(mark) - # pops [mark, chk_depth) and frees those blocks. A stale pointer with a still-odd - # header would pass the checks above, so require the block to sit in the live - # window [0, chk_depth). Once chk_stack is full (chk_depth == chk_cap) new blocks - # are no longer recorded, so the check is skipped to avoid rejecting valid frees. - if self.chk_stack is not None and self.chk_depth < self.chk_cap: + # Live-set check (diagnostic, --detection only): every alloc pushes its block onto + # chk_stack, and reset_to(mark) pops [mark, chk_depth) and frees those blocks. A stale + # pointer with a still-odd header would pass the checks above, so require the block to + # sit in the live window [0, chk_depth). The scan is O(chk_depth): a pool that is never + # reset (PermPool) grows the window without bound (5M entries observed), so running it on + # every free made the type-interning frees O(N^2) and stretched one file's translation to + # minutes. The check is the same class of aid as --detection, so it is gated on it; the + # production path stays O(1) and still rejects re-frees via the header parity test above. + if self.detection != 0 and self.chk_stack is not None and self.chk_depth < self.chk_cap: alive: int = 0 for ci in range(int(self.chk_depth)): if self.chk_stack[ci] == uint64(block):