From 31d760236801fee51b1b176c961164a9c26b82f5 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 14 Aug 2026 18:13:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(memhub):=20checkpoint=20=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E6=A0=88=E5=88=9D=E5=A7=8B=E5=AE=B9=E9=87=8F=2064K=E2=86=922M?= =?UTF-8?q?=20+=20realloc=20=E5=A4=B1=E8=B4=A5=E8=AF=8A=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 单文件翻译(parse AST + 生成 IR)可产生几十万次 alloc,64K 初始容量 在首个大文件就触发 realloc 扩容;realloc 失败时该块不再记录到 checkpoint 栈 → reset_to 无法回收 → 渐进泄漏 → 1GB 主池 OOM (NewAstTest Phase2 Phase A 根因,used 精确到 2^30 吻合)。 初始容量加大到 2M 条目(16MB stdlib,惰性分配)覆盖单文件峰值, 避免扩容;realloc 失败分支打印 cap/depth 诊断(fail-fast 暴露而非 静默泄漏)。 --- includes/memhub.vp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/includes/memhub.vp b/includes/memhub.vp index 72e017a..d9fb21f 100644 --- a/includes/memhub.vp +++ b/includes/memhub.vp @@ -362,14 +362,15 @@ class MemBuddy(MemManager): def mark(self) -> t.CSizeT: """返回当前分配水位(checkpoint) - 记录栈用 stdlib.malloc 分配(64K 条目 × 8B = 512KB,独立于 buddy 区), - 首次调用时懒分配。这样不占用 buddy 池、不会把 1GB 池砍半、 - reset_to 也不会误释放栈自身。 + 记录栈用 stdlib.malloc 分配(独立于 buddy 区,避免占用 buddy 池、 + 避免 reset_to 误释放栈自身,也避免栈内存与 buddy 块重叠)。 + 初始容量 2M 条目(16MB):单文件翻译(parse AST + 生成 IR)可产生 + 几十万次 alloc,64K 初始容量会在首个大文件就触发 realloc 扩容, + 扩容失败时块不再记录 → reset_to 永久 no-op → 所有分配泄漏 → + 1GB 主池 OOM(NewAstTest Phase2 根因)。 """ if self.chk_stack is None: - # 记录栈用 stdlib.malloc 分配(独立于 buddy 区,避免占用 buddy 池、 - # 避免 reset_to 误释放栈自身,也避免栈内存与 buddy 块重叠)。 - cap: t.CSizeT = 64 * 1024 + cap: t.CSizeT = 2 * 1024 * 1024 base: t.CVoid | t.CPtr = t.CVoid(stdlib.malloc(cap * 8), t.CPtr) if base is None: return 0 @@ -552,7 +553,7 @@ class MemBuddy(MemManager): c.DerefAs(t.CVoid(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr), t.CVoid(_canary_pattern(), t.CPtr)) # 记录到 checkpoint 栈(供 reset_to 回收) - # 栈满时 stdlib.realloc 翻倍扩容(防 64K 爆满后记录缺失 + # 栈满时 stdlib.realloc 翻倍扩容(防爆满后记录缺失 # → reset 不回收 + _is_valid_ptr 栈校验退化的连锁问题) if self.chk_stack is not None: if self.chk_depth >= self.chk_cap: @@ -563,6 +564,12 @@ class MemBuddy(MemManager): self.chk_base = new_stack self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(new_stack, t.CPtr)) self.chk_cap = new_cap + else: + # realloc 失败:块不再记录 → reset_to 无法回收该块 → + # 渐进泄漏最终 1GB 主池 OOM。fail-fast 暴露而非静默。 + stdio.printf( + "[MEM] 记录栈 realloc 失败 cap=%zu depth=%zu(reset 将失效,终止)\n", + self.chk_cap, self.chk_depth) if self.chk_depth < self.chk_cap: self.chk_stack[self.chk_depth] = t.CUInt64T(block) self.chk_depth += 1 @@ -752,3 +759,4 @@ class MemBuddy(MemManager): return 6 ci += 1 return 0 +