Files
endorphin-tessera-gui/examples/gc-lifecycle.endor
T

60 lines
3.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 托管对象循环与等待帧回收:先记 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。
// 按 mountCycle → 观察 → releaseCycle 的顺序使用;未释放前重复 mountCycle 会另建页面并覆盖 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))