mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 08:04:45 +00:00
fix(perf): collect debug memory snapshot off the main thread
The debug-only MemoryUsageChip ("X/YMB" top-bar indicator, gated on
isDebug) polls collectMemorySnapshot() every 2s from a produceState
block, which runs on the main thread. That reads coil3.disk.DiskLruCache
.size(), a @Synchronized call. On cold start the Coil disk cache holds
that monitor for several seconds (journal init + the burst of image
writes from the initial relay event flood), so the UI thread blocked
inside size() — the "Loading account" frame couldn't repaint until it
returned. Profiling showed a single ~8s render frame and the UI thread
"blocking from coil3.disk.DiskLruCache.size()".
Collect the snapshot via withContext(Dispatchers.IO) so the synchronized
read blocks a background thread instead of the UI. The "Loading account"
stall on cold start drops from ~15-20s to ~5s. Debug-only path, so this
never affected release builds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9d0f444b6f
commit
de1362561f
+8
-1
@@ -41,7 +41,9 @@ import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.MemorySnapshot
|
||||
import com.vitorpamplona.amethyst.collectMemorySnapshot
|
||||
import com.vitorpamplona.amethyst.isDebug
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun MemoryUsageChip() {
|
||||
@@ -52,7 +54,12 @@ fun MemoryUsageChip() {
|
||||
|
||||
val snapshot by produceState<MemorySnapshot?>(null) {
|
||||
while (true) {
|
||||
value = collectMemorySnapshot(context)
|
||||
// collectMemorySnapshot reads coil3.disk.DiskLruCache.size(), which is @Synchronized and
|
||||
// contends with the disk cache's own journal I/O. On cold start that lock is held by a
|
||||
// background worker for seconds (initial journal read + the burst of image writes), so
|
||||
// running this on the produceState default (main) dispatcher froze the UI thread —
|
||||
// the "Loading account" frame couldn't repaint until size() returned. Collect off-main.
|
||||
value = withContext(Dispatchers.IO) { collectMemorySnapshot(context) }
|
||||
delay(2_000)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user