fix: test262 runner 进程 RSS 无界增长——session 收尾统一释放内建裸堆区/upvalue 别名 + 每测试分配上限 256MiB(任务 116)

- 泄漏修复:KernelSession 收尾(teardown_intrinsic_protos/free_session_upvalues)
  释放内建对象 Box::into_raw 裸堆区(release_raw_heap 四区置空幂等)与
  session upvalue 原件/晋升克隆别名去重释放;bindings 原生盒负载边、
  session_gc 边记录、vm_props 属性区同步收尾
- 失控测试封顶:runner kernel max_alloc_bytes=256MiB(dispatch 采样口径
  run_alloc_bytes/run_alloc_bytes_full),超限计 memory-limit 失败而非拖垮
  进程 RSS(arena 高水位 GB 级 × 多 worker = 宿主 OOM)
- 归属:RSS 泄漏 pre-existing(HEAD 无 WIP 同现);identifiers escaped
  unicode 挂死族另立 B132(pre-existing,supervise 超时自愈)
- 验证:build/clippy/四 crate 测试全绿零新增告警;language 前 5000 测试
  单窗峰值 330MB(旧 ~4.5MB/测试 单调增长→88GB OOM 签名消失),
  窗口间峰值 0.17-1.6GB 有界、逐测试释放回基线
This commit is contained in:
2026-09-11 03:55:59 +00:00
parent a5258f2739
commit 227dfe008f
19 changed files with 566 additions and 100 deletions
+20
View File
@@ -870,6 +870,7 @@ fn classify_vm_error(e: &str, neg: Option<&Negative>, no_skip: bool) -> TestOutc
|| e.contains("not supported")
|| e.contains("unsupported")
|| e.contains("step limit")
|| e.contains("memory limit")
|| e.contains("NEW_EXPRESSION")
|| e.contains("GET_PROP_DYNAMIC on non-object")
|| e.contains("SET_PROP_DYNAMIC on non-object")
@@ -1467,6 +1468,11 @@ fn build_runner_kernel() -> Arc<KernelCore> {
kernel_config.max_call_depth = 256;
kernel_config.min_pool_size = 1;
kernel_config.max_pool_size = Some(1);
// 单测试分配上限:死循环类测试触步数上限时持续分配,arena 高水位可达 GB
// 级;多 worker 并发下进程 RSS 包络被各 worker 当前高水位顶起,全量运行
// 必然 OOM。正规测试峰值 ≤132MB(Array 块 p100 实测),256MiB 留有余量
// 且把失控测试的驻留面封顶到上限本身。
kernel_config.max_alloc_bytes = Some(256 * 1024 * 1024);
KernelCore::new(kernel_config)
}
@@ -1509,6 +1515,8 @@ fn categorize_fail(msg: &str) -> (String, String) {
("vm: not yet implemented".into(), String::new())
} else if reason.contains("step limit") {
("vm: step limit".into(), String::new())
} else if reason.contains("memory limit") {
("vm: memory limit".into(), String::new())
} else if reason.contains("not defined") {
("vm: not defined".into(), parse_undefined_ident(msg).unwrap_or("").to_string())
} else if reason.contains("unsupported") {
@@ -1933,6 +1941,14 @@ mod tests {
}
}
/// 分配上限超限(与步数上限同款运行期限制):默认 skip,`--no-skip` 下 fail。
#[test]
fn memory_limit_errors_skip_by_default() {
let e = "vm error: VM memory limit 268435456 exceeded (used 268436480) at pc=14";
assert_outcome(e, None, false, &TestOutcome::Skip("".into()));
assert_outcome(e, None, true, &TestOutcome::Fail("".into()));
}
/// 能力未实现形态保留 skip;`--no-skip` 下转 fail。
#[test]
fn unimplemented_shapes_stay_skipped() {
@@ -2030,6 +2046,10 @@ mod tests {
("uncaught ReferenceError: foo is not defined", ("vm: not defined", "foo")),
("compile error: Identifier 'x' is not defined", ("compile: not defined", "x")),
("vm error: IC_GET_PROP on non-object", ("vm: IC_GET_PROP on non-object", "")),
(
"vm error: VM memory limit 268435456 exceeded (used 268436480) at pc=14",
("vm: memory limit", ""),
),
("vm error: TypeError: method called on incompatible receiver", ("vm: other", "")),
("engine panic: boom", ("engine panic", "")),
(