perf(memory): release Go heap and decoded image caches on OS memory pressure

This commit is contained in:
zarzet
2026-07-14 09:09:42 +07:00
parent f983a303fd
commit 96eb412fe5
4 changed files with 41 additions and 0 deletions
+17
View File
@@ -12,6 +12,7 @@ import 'package:spotiflac_android/providers/library_collections_provider.dart';
import 'package:spotiflac_android/providers/local_library_provider.dart';
import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/services/notification_service.dart';
import 'package:spotiflac_android/services/platform_bridge.dart';
import 'package:spotiflac_android/services/share_intent_service.dart';
import 'package:spotiflac_android/services/cover_cache_manager.dart';
import 'package:spotiflac_android/utils/local_library_scan_prefs.dart';
@@ -157,9 +158,25 @@ class _EagerInitializationState extends ConsumerState<_EagerInitialization>
ref.read(downloadQueueProvider.notifier).flushQueuePersistence(),
);
}
// Backgrounded: return the Go heap's high-water mark to the OS so the
// process is a smaller kill target.
unawaited(PlatformBridge.releaseNativeMemory());
}
}
@override
void didHaveMemoryPressure() {
// OS memory pressure: drop decoded bitmaps (disk caches stay intact) and
// have the Go side release freed heap back to the OS.
final imageCache = PaintingBinding.instance.imageCache;
imageCache.clear();
imageCache.clearLiveImages();
if (CoverCacheManager.isInitialized) {
CoverCacheManager.instance.store.emptyMemoryCache();
}
unawaited(PlatformBridge.releaseNativeMemory());
}
void _initializeDeferredProviders() {
_downloadHistoryWarmupTimer = _scheduleProviderWarmup(
const Duration(milliseconds: 400),
+8
View File
@@ -1202,6 +1202,14 @@ class PlatformBridge {
await _channel.invokeMethod('clearLogs');
}
/// Ask the Go backend to GC and return freed heap to the OS. Best-effort:
/// safe to call on memory pressure or when the app is backgrounded.
static Future<void> releaseNativeMemory() async {
try {
await _channel.invokeMethod('releaseMemory');
} catch (_) {}
}
static Future<int> getGoLogCount() async {
final result = await _channel.invokeMethod('getLogCount');
return result as int;