From 7c7629852a17e387f00b3fc17b229fa9caa54cf2 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 25 Aug 2026 16:21:34 +0800 Subject: [PATCH] =?UTF-8?q?perf(memhub):=20detection=20=E9=87=87=E6=A0=B7?= =?UTF-8?q?=E6=8E=A2=E6=B5=8B=EF=BC=8CO(n=C2=B2)=20=E9=99=8D=E4=B8=BA=20O(?= =?UTF-8?q?n=C2=B2/256)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 每次 alloc 全表扫描(分配重叠 + _det_probe)是 O(n) ,2M 次 alloc = O(n²),detection 模式过慢。 改为每 MEMBUDDY_DET_PROBE_PERIOD(256) 次 alloc 采样扫描一次;记录追加保持 O(1)。损坏是持久性的,不依赖即时扫描,检测能力不损失。 --- includes/memhub.vp | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/includes/memhub.vp b/includes/memhub.vp index db701ce..beb0f20 100644 --- a/includes/memhub.vp +++ b/includes/memhub.vp @@ -47,6 +47,11 @@ MEMBUDDY_FILL_PATTERN: t.CDefine = 0xCD MEMBUDDY_DET_MARKER: t.CDefine = 0xCDCD # 检测记录区默认大小(32MB,每条记录 {ptr u64, size u64} = 16B) MEMBUDDY_DET_RECORD_SIZE: t.CDefine = 33554432 +# 采样周期(2 的幂):每 N 次 alloc 做一次全表扫描(分配重叠 + 探测)。 +# 记录追加本身 O(1) 不受影响;损坏是持久性的,不依赖即时扫描,采样 +# 不损失检测能力——2M 次 alloc 若每次全表 O(n) 扫描 = O(n²) 太慢 +# (用户反馈 detection 模式过慢),采样把扫描次数降为 1/N。 +MEMBUDDY_DET_PROBE_PERIOD: t.CDefine = 256 def _canary_pattern() -> t.CUInt64T: @@ -674,20 +679,25 @@ class MemBuddy(MemManager): m_t_d: t.CUInt16T | t.CPtr = (t.CUInt16T | t.CPtr)(t.CVoid(tail_d, t.CPtr)) m_t_d[0] = t.CUInt16T(MEMBUDDY_DET_MARKER) if self._det_records is not None: - # 分配重叠即时检测:新块地址是否已在 active 记录(同一块重复 - # 分配实锤——SlotsBugTest 7B buf 与 72B Token 同 ptr、cargs - # 只写 0/40 根因)。重叠 = MemBuddy free list 损坏(active 块 - # 混入 free list),在第一次重叠处拦截并打印两个 size。 - ff_d: t.CUInt64T = t.CUInt64T(1) << 63 - dup_i: t.CSizeT = 0 - while dup_i < self._det_count: - drp: t.CUInt64T = self._det_records[dup_i * 2] - drs: t.CUInt64T = self._det_records[dup_i * 2 + 1] - if drp == base_ret_d + 2 and (drs & ff_d) == 0: - stdio.printf("[DET] 分配重叠: 新alloc(size=%llu)与记录[%zu](sz=%llu)同地址 ptr=%llu(同一块重复分配,free list 损坏)\n", - t.CUInt64T(size), dup_i, drs & (ff_d - 1), base_ret_d + 2) - stdlib.exit(1) - dup_i += 1 + # 采样:每 MEMBUDDY_DET_PROBE_PERIOD 次 alloc 做一次全表扫描 + # (分配重叠 + 探测),其余只追加记录(O(1))。损坏是持久性的, + # 不依赖即时扫描——2M 次 alloc 若每次全表 O(n) = O(n²) 太慢 + # (用户反馈 detection 模式过慢),采样把扫描降为 O(n²/PERIOD)。 + if (self._det_count & (MEMBUDDY_DET_PROBE_PERIOD - 1)) == 0: + # 分配重叠即时检测:新块地址是否已在 active 记录(同一块重复 + # 分配实锤——SlotsBugTest 7B buf 与 72B Token 同 ptr、cargs + # 只写 0/40 根因)。重叠 = MemBuddy free list 损坏(active 块 + # 混入 free list),在第一次重叠处拦截并打印两个 size。 + ff_d: t.CUInt64T = t.CUInt64T(1) << 63 + dup_i: t.CSizeT = 0 + while dup_i < self._det_count: + drp: t.CUInt64T = self._det_records[dup_i * 2] + drs: t.CUInt64T = self._det_records[dup_i * 2 + 1] + if drp == base_ret_d + 2 and (drs & ff_d) == 0: + stdio.printf("[DET] 分配重叠: 新alloc(size=%llu)与记录[%zu](sz=%llu)同地址 ptr=%llu(同一块重复分配,free list 损坏)\n", + t.CUInt64T(size), dup_i, drs & (ff_d - 1), base_ret_d + 2) + stdlib.exit(1) + dup_i += 1 if self._det_count >= self._det_cap: # 记录表满:stdlib.realloc 翻倍扩容(防 is_alive/_det_probe # 因容量耗尽漏检——SlotsBugTest 编译 includes 超 2M 次 alloc, @@ -703,7 +713,8 @@ class MemBuddy(MemManager): self._det_records[self._det_count * 2] = base_ret_d + 2 self._det_records[self._det_count * 2 + 1] = t.CUInt64T(size) self._det_count += 1 - self._det_probe() + if (self._det_count & (MEMBUDDY_DET_PROBE_PERIOD - 1)) == 0: + self._det_probe() result = t.CVoid(base_ret_d + 2, t.CPtr) if result is None: # 分配失败诊断(定位"异常 size/池耗尽导致 None → 调用方解引用段错误")