WebView2のメモリが高く見える時はTask ManagerとV8 heap snapshotを比べる
WebView2、Tauri、似たWebView stackで作ったdesktop appは、Task Manager上でメモリを多く使っているように見えます。しかし、それだけでJavaScript heapがleakしているとは限りません。
V8はobjectを回収した後もOS pageを保持することがあります。Task Managerはprocess memoryを示します。live JavaScript objectが増え続けているかは分かりません。
state layerを書き換える前に、Task Managerとheap snapshotを比較します。
false-positive leak
よくある観測です。
Task Manager:
app process grows from 120 MB to 260 MB
App behavior:
no obvious slowdown
no growing list in UI
clearing data does not immediately lower RSS
これはV8の通常のmemory behaviorである可能性があります。V8は再利用のためにmemory pagesをOSへすぐ返さないことがあります。
必要なのはprocess RSSだけではなく、live JavaScript heapです。
heap snapshotを取る
WebView2 instanceへEdgeまたはChrome DevToolsでattachします。
- WebViewのDevToolsを開く
- Memory panelへ行く
- heap snapshotを取る
- leakが疑われる操作後にもう一度取る
- retained objectsとheap sizeを比べる
Task Managerは高いがheap snapshotが小さく安定しているなら、JS object leakとは言い切れません。V8のpage retentionかもしれません。
Task Managerもheap snapshotも単調増加するなら、leakの根拠が強くなります。
高頻度state updateはGC pressureを作る
永久leakでなくても、高頻度updateはmemoryとCPUを悪く見せます。
desktop toolではよくあります。
- serial logs
- terminal output
- file watcher streams
- telemetry graphs
- build logs
- trace viewers
非効率なpatternです。
socket.onmessage = (event) => {
useLogStore.setState((state) => ({
lines: [...state.lines, event.data],
}));
};
毎秒何十回も配列を作り直すと、短命objectが大量に生まれます。
bufferしてUI速度でflushする
ReactやZustand更新の前にbatchします。
const buffer: string[] = [];
socket.onmessage = (event) => {
buffer.push(event.data);
};
setInterval(() => {
if (buffer.length === 0) return;
const batch = buffer.splice(0, buffer.length);
useLogStore.setState((state) => ({
lines: [...state.lines, ...batch].slice(-10_000),
}));
}, 200);
state writeを「eventごと」から「毎秒5回」へ減らせます。logやmonitoring viewなら200ms程度は十分responsiveです。
使われていないstore fieldを消す
ZustandやRedux storeに、もうcomponentが読まないfieldが残っていることがあります。毎回copyされるなら、未使用でもallocationに効きます。
rg "unusedFieldName" src
componentが読まず、persistence formatにも必要ないなら削除します。特にdead arrayは高頻度update pathで高コストです。
leak診断とoptimizationを分ける
判断ルールです。
RSS high, heap stable
-> JS leakの証拠としては弱い
-> performanceが悪いならupdate frequencyを最適化
RSS high, heap grows, retained objects grow
-> JS retention leakの可能性が高い
-> retaining pathを見る
CPU high, heap stable
-> update/render pressureの可能性
-> batch events and reduce renders
Task ManagerだけでWebView2 appをleak扱いしないことです。