JavaScript中的Liveness是什么?ECMAScript规范GC相关概念疑问
核心概念解读
WeakRef-oblivious execution 是ECMAScript规范为了界定对象活性、给GC实现留下弹性空间而设计的思想实验判定规则,本身不代表实际执行逻辑,你之前的两个理解存在偏差,下面结合规则和示例拆解:
先澄清规则的底层逻辑
规范设计这个假设场景的本质是:假装所有指向集合S中对象的WeakRef都已经失效(调用deref全返回undefined),再判断后续代码是否还能通过WeakRef之外的途径观测到S中对象的存在。
- 如果能观测到:说明S中的对象存在强引用,属于live对象,不能被回收
- 如果不能观测到:说明S中的对象只有WeakRef指向,允许被GC回收
注意:这个假设场景只是判定活性的工具,并不是说S中的对象真的已经被回收,也不代表实际执行时的行为。
结合示例理解
示例1:存在强引用的情况
// 强引用持有对象 const user = { name: "test" }; // 创建WeakRef,user进入当前代理的[[KeptAlive]]列表 const userWr = new WeakRef(user); // 同步任务结束后[[KeptAlive]]列表清空,此时假设S = {user} // 模拟WeakRef-oblivious执行场景:userWr.deref()永远返回undefined // 但后续代码可以直接通过user变量访问对象值,不需要依赖WeakRef就能观测到user的存在 // 因此满足live判定条件,user不会被回收
示例2:仅存在WeakRef的情况
let user = { name: "test" }; const userWr = new WeakRef(user); // 断开唯一强引用 user = null; // 同步任务结束后[[KeptAlive]]列表清空,此时假设S = {原user对象} // 模拟WeakRef-oblivious执行场景:userWr.deref()永远返回undefined // 此时全代码没有任何其他途径可以访问原user对象,完全观测不到它的存在 // 因此不满足live判定条件,原user对象可以被GC回收
示例3:[[KeptAlive]]列表的作用
// 直接创建匿名对象的WeakRef const wr = new WeakRef({ id: 123 }); // 同个同步任务内调用deref console.log(wr.deref()); // 100%返回{id:123},因为对象还在[[KeptAlive]]列表中,满足live的第一个判定条件 // 等到下一个异步任务执行时 setTimeout(() => { console.log(wr.deref()); // 可能返回undefined,因为[[KeptAlive]]已经清空,该对象只有WeakRef指向,允许被回收 }, 0);
对你疑问的直接回应
- 这个定义没有隐含S中所有对象都应该被回收,它只是先假设「所有指向S的WeakRef都失效」的前提,再反过来判断S中对象有没有其他存活依据。
- 这个假设场景也不是指S中还有未被回收、可被WeakRef观察到的对象,恰恰相反,它的前提是所有指向S的WeakRef都失效,如果你还能观察到S中的对象,只能说明你用的不是WeakRef,对象还有强引用。
内容的提问来源于stack exchange,提问作者Ilya Loskutov
相关产品推荐
相关产品推荐

