59 lines
3.5 KiB
Plaintext
59 lines
3.5 KiB
Plaintext
// 托管对象循环与等待帧回收:先记 ui.stats().objects,再调用 mountCycle,观察 phase 与 pending.value.status()。
|
||
// 关闭临时页仍可因业务引用保留等待任务;releaseCycle 清掉外部引用后,缓存不应让整个引用环常驻。
|
||
// 比较操作前后对象数时,关闭页面只解除展示根;holder/pending 外部引用也释放后才应回到基线。
|
||
holder = ui.state(0)
|
||
// pending.value 后续保存 Task;它和 holder.value 保存的 Page 是两条需要显式清除的外部可达路径。
|
||
pending = ui.state(0)
|
||
phase = ui.state(0)
|
||
// 通过 peer 指回包含自己的 Page,配合等待协程形成包含视觉缓存读依赖的引用环。
|
||
class CycleRect: RectBlock {
|
||
// 指回 transient 页面;页面又通过 render 的根保留 rect,形成真实托管对象环。
|
||
peer: Object
|
||
// sleep 归属该 rect,await 保留协程帧;先写 phase=1,只有实际恢复后才写 2 并改 Page 标题。
|
||
function wait(self: CycleRect): Unit {
|
||
// ui.spawn 调用绑定 wait,sleep 的 owner 仍是同一 rect,键 sleep 与外层 workflow 任务键不同。
|
||
gate = ui.sleep(self,"sleep",300000)
|
||
phase.set(1)
|
||
// 在 gate 完成前挂起此调用,下面两条写入尚未执行;done 只是保存恢复结果,本例不读取它。
|
||
done = await gate
|
||
phase.set(2)
|
||
self.peer.title = "等待已结束"
|
||
}
|
||
// 故意读取 peer.title,让布局依赖包含循环中的 Page;缓存应借用观察,不增加长期 GC 根。
|
||
function measure(self: CycleRect, mount: Mount, constraints: Constraints): MeasureResult {
|
||
// source_layout 的只读测量调用;observed 虽不参与数值计算,成员访问仍是需要跟踪的实际读取。
|
||
observed = self.peer.title
|
||
return MeasureResult(180,40)
|
||
}
|
||
// 绘制也读取 peer.title,检查绘制缓存与等待帧不会共同意外保活循环。
|
||
function paint(self: CycleRect, mount: Mount, geometry: Bounds): DisplayList {
|
||
// source_paint 的只读计算也读取环中页面;委托基类生成绘制数据,不把 Page 放进输出命令。
|
||
observed = self.peer.title
|
||
return RectBlock.paint(self,mount,geometry)
|
||
}
|
||
}
|
||
// 创建临时 Page 和 CycleRect,相互引用后挂载,再把 Page/Task 分别放入两个外部 holder。
|
||
function mountCycle(): Unit {
|
||
// 供 Console 手工调用的零参入口,加载此文件只定义函数,不立即创建临时环或开始五分钟等待。
|
||
transient = Page()
|
||
transient.title = "临时引用环"
|
||
rect = CycleRect(180,40,8,"#3868D9",transient)
|
||
transient.render(rect)
|
||
holder.set(transient)
|
||
phase.set(0)
|
||
// spawn 返回工作流 Task 立即存入 pending,等待期间可经 pending.value.status() 观察,不能在此同步等完成。
|
||
pending.set(ui.spawn(rect,"workflow",rect.wait))
|
||
}
|
||
// 先关闭临时页,随后去掉两个外部引用;等待依赖无需等满五分钟,失去可达性后应整体回收。
|
||
function releaseCycle(): Unit {
|
||
// 应在 mountCycle 建立 holder 后由 Console 调用;close 先解除展示关系,再清除外部 Page 与 Task 引用。
|
||
holder.value.close()
|
||
holder.set(0)
|
||
pending.set(0)
|
||
}
|
||
// 基线页面始终存在,用它比较操作前后的托管对象数,不把临时页面当作基线。
|
||
base = Page()
|
||
// base/holder/pending/phase 这些顶层对象仍保留,比较 GC 数量时不能要求整个会话回到零对象。
|
||
base.title = "GC 基线"
|
||
base.render(TextBlock("关闭临时 Page 后应回收引用环",2))
|