From 09aeb733e64b69647e55692442ce51ab3725b8f1 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Fri, 21 Aug 2026 06:01:15 -0300 Subject: [PATCH] Trim image and trust-score caches on memory pressure Coil 3 registers no ComponentCallbacks of its own, so its 32MB bitmap memory cache stayed fully resident in this long-lived signer process even with the UI invisible and under system memory pressure. onTrimMemory now clears the Coil memory cache on TRIM_MEMORY_UI_HIDDEN and, additionally, TrustScoreService's cache from TRIM_MEMORY_BACKGROUND up. Since API 34 the deprecated RUNNING_*/ MODERATE/COMPLETE levels are never delivered, so onLowMemory is overridden as the foreground-pressure stand-in (verified against the SDK 36 android.jar: only UI_HIDDEN and BACKGROUND are non-deprecated). Also ignores the local trace_processor wrapper downloaded for the heapprofd profiling session. --- .gitignore | 2 + .../java/com/greenart7c3/nostrsigner/Amber.kt | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/.gitignore b/.gitignore index d34257dd..e654a1ee 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,5 @@ lint/tmp/ # lint/reports/ quartz/ .ai-jail +trace_processor +perf-traces diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/Amber.kt b/app/src/main/java/com/greenart7c3/nostrsigner/Amber.kt index a94a8ef9..d782f3e8 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/Amber.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/Amber.kt @@ -54,6 +54,7 @@ import com.greenart7c3.nostrsigner.service.ConnectivityService import com.greenart7c3.nostrsigner.service.NotificationSubscription import com.greenart7c3.nostrsigner.service.ProfileSubscription import com.greenart7c3.nostrsigner.service.TorManager +import com.greenart7c3.nostrsigner.service.TrustScoreService import com.greenart7c3.nostrsigner.service.UpdateCheckWorker import com.greenart7c3.nostrsigner.service.ZapstoreUpdater import com.greenart7c3.nostrsigner.service.crashreports.CrashReportCache @@ -630,6 +631,44 @@ class Amber : .build() } + override fun onTrimMemory(level: Int) { + super.onTrimMemory(level) + + // Since API 34 the system only delivers UI_HIDDEN and BACKGROUND here — + // the RUNNING_*/MODERATE/COMPLETE levels are deprecated and never sent. + // UI_HIDDEN (20) is not pressure, but a long-lived signer process has no + // reason to keep UI-only caches while its UI is invisible either. + if (level == TRIM_MEMORY_UI_HIDDEN) { + trimImageMemoryCache() + } else if (level >= TRIM_MEMORY_BACKGROUND) { + trimImageMemoryCache() + TrustScoreService.clearCache() + } + } + + /** + * Pre-API-34 stand-in for foreground memory pressure (the deprecated + * TRIM_MEMORY_RUNNING_* levels are never delivered since API 34): the + * system only calls this when memory is low enough that process death is + * imminent. + */ + override fun onLowMemory() { + super.onLowMemory() + trimImageMemoryCache() + TrustScoreService.clearCache() + } + + private fun trimImageMemoryCache() { + // Coil 3 registers no ComponentCallbacks of its own, so its bitmap + // memory cache (32 MB cap) would otherwise stay fully resident in + // this long-lived signer process even while its UI is not visible. + // The cache rebuilds lazily on the next image load. + applicationIOScope.launch { + runCatching { SingletonImageLoader.get(this@Amber).memoryCache?.clear() } + .onFailure { AmberLog.w(TAG, "Failed to trim Coil memory cache", it) } + } + } + override fun onTerminate() { super.onTerminate() applicationIOScope.cancel()