49 lines
2.3 KiB
Plaintext
49 lines
2.3 KiB
Plaintext
// 托管对象循环与等待帧回收:先记 ui.stats().objects,再调用 mountCycle,观察 phase 与 pending.value.status()。
|
||
// 关闭临时页仍可因业务引用保留等待任务;releaseCycle 清掉外部引用后,缓存不应让整个引用环常驻。
|
||
// 比较操作前后对象数时,关闭页面只解除展示根;holder/pending 外部引用也释放后才应回到基线。
|
||
holder = ui.state(0)
|
||
pending = ui.state(0)
|
||
phase = ui.state(0)
|
||
// 通过 peer 指回包含自己的 Page,配合等待协程形成包含视觉缓存读依赖的引用环。
|
||
class CycleRect: RectBlock {
|
||
peer: Object
|
||
// sleep 归属该 rect,await 保留协程帧;先写 phase=1,只有实际恢复后才写 2 并改 Page 标题。
|
||
function wait(self: CycleRect): Unit {
|
||
gate = ui.sleep(self,"sleep",300000)
|
||
phase.set(1)
|
||
done = await gate
|
||
phase.set(2)
|
||
self.peer.title = "等待已结束"
|
||
}
|
||
// 故意读取 peer.title,让布局依赖包含循环中的 Page;缓存应借用观察,不增加长期 GC 根。
|
||
function measure(self: CycleRect, mount: Mount, constraints: Constraints): MeasureResult {
|
||
observed = self.peer.title
|
||
return MeasureResult(180,40)
|
||
}
|
||
// 绘制也读取 peer.title,检查绘制缓存与等待帧不会共同意外保活循环。
|
||
function paint(self: CycleRect, mount: Mount, geometry: Bounds): DisplayList {
|
||
observed = self.peer.title
|
||
return RectBlock.paint(self,mount,geometry)
|
||
}
|
||
}
|
||
// 创建临时 Page 和 CycleRect,相互引用后挂载,再把 Page/Task 分别放入两个外部 holder。
|
||
function mountCycle(): Unit {
|
||
transient = Page()
|
||
transient.title = "临时引用环"
|
||
rect = CycleRect(180,40,8,"#3868D9",transient)
|
||
transient.render(rect)
|
||
holder.set(transient)
|
||
phase.set(0)
|
||
pending.set(ui.spawn(rect,"workflow",rect.wait))
|
||
}
|
||
// 先关闭临时页,随后去掉两个外部引用;等待依赖无需等满五分钟,失去可达性后应整体回收。
|
||
function releaseCycle(): Unit {
|
||
holder.value.close()
|
||
holder.set(0)
|
||
pending.set(0)
|
||
}
|
||
// 基线页面始终存在,用它比较操作前后的托管对象数,不把临时页面当作基线。
|
||
base = Page()
|
||
base.title = "GC 基线"
|
||
base.render(TextBlock("关闭临时 Page 后应回收引用环",2))
|