Release retained engine memory
WebAssembly linear memory grows but does not shrink after cells or stores are cleared. When your application is idle after a large import, clear, or workbook disposal, call releaseEngineMemory explicitly. Sheetwrite never schedules a release automatically.
The call waits for synchronous transactions and active datasource page loads, then moves all live stores together into a fresh instance of the selected engine. Cell sources, styles, cached formula results (including volatile results), resident datasource pages, unsaved dirty edits, and compact undo/redo history survive. Unloaded clean pages remain unloaded and can be fetched again from the datasource. Worker renderers rebuild their frames without document-change events.
The main-thread pause scales with resident cells and compact history, so do not invoke it on an interaction-critical path. Migration temporarily needs both instances and packed transfer buffers; it can increase peak memory before garbage collection reclaims the retired instance. If preparation fails, every live store stays on the original instance. Concurrent calls share the same release.
report.wasmBytesBefore and report.wasmBytesAfter are committed linear-memory bytes, not live-cell bytes or process memory. report.pauseMs measures migration, excluding the idle wait. A release is not guaranteed to reduce committed bytes: surviving data, compact history, and migration scratch can still require substantial memory. Actual process-memory reclamation depends on garbage collection.
Runtime resource ownership
The performance showcase at /showcases/performance#resource-ownership renders the public RuntimeResourceSnapshot protocol directly. It keeps exclusive-owner logical bytes, allocated capacity, WASM committed pages, and independent browser runtime observations in separate buckets; committed pages are never summed into live payload. Bulk-edit before/settled deltas use diffRuntimeResourcePhases and omit unchanged owners.
The UI and this reference share RUNTIME_RESOURCE_SCHEMA_VERSION. Detailed peak phases remain in the validated benchmark artifact rather than being presented as measurements from the visitor's browser.
String collection reclaims obsolete pool text and densely remaps surviving IDs. Automatic collection runs only at committed edit transaction barriers, never during painting or page loading, when dead arena/span storage exceeds 256 KiB and the surviving arena/span storage. Growth-based backoff avoids repeatedly scanning unchanged live data. Bulk clears and sheet removal request a new threshold check at the next commit.
compactStringStorage() explicitly collects unreachable text and trims growth slack outside an active mutation/page load. Raw IDs are valid only within stringPoolEpoch(); retain the epoch with projections and invalidate caches on a change, as described in the worker rendering guide. History snapshots own captured text. Persist resolved values, not pool IDs. Reclaimed Rust ownership does not imply that WebAssembly committed linear memory shrinks.
Reproduce and validate the full owner/operation matrix with:
bun run --filter @sheetwrite/bench bench:resource