// memory_monitor.dart // 强化版内存监控工具类 import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; import 'package:puzzleweave/firebase/firebase_helper.dart'; import 'package:puzzleweave/models/download.dart'; final Logger _log = Logger('MemoryMonitor'); /// 内存阶段定义 enum MemoryState { normal, warning, critical } class MemoryMonitor with WidgetsBindingObserver { static final MemoryMonitor _instance = MemoryMonitor._internal(); factory MemoryMonitor() => _instance; MemoryMonitor._internal(); Timer? _monitorTimer; int _warningCount = 0; // 防止系统内存压力信号死循环 DateTime? _lastSystemPressureTime; static const _systemPressureCooldown = Duration(seconds: 10); // 动态生成的阈值 double _warningThreshold = 180.0; double _criticalThreshold = 250.0; VoidCallback? _onHighMemory; VoidCallback? _onCriticalMemory; // Release模式下的内存显示 static final ValueNotifier memoryDisplay = ValueNotifier('Memory: 0MB'); /// 初始化并启动监控 void startMonitoring({Duration interval = const Duration(seconds: 30), VoidCallback? onHighMemory, VoidCallback? onCriticalMemory}) { _onHighMemory = onHighMemory; _onCriticalMemory = onCriticalMemory; // 1. 注册系统内存压力监听 (WidgetsBindingObserver) WidgetsBinding.instance.addObserver(this); // 2. 根据设备情况初始化动态阈值 _initializeDynamicThresholds(); // 3. 启动定时轮询 _monitorTimer?.cancel(); _monitorTimer = Timer.periodic(interval, (_) => _checkMemory()); _log.info('Memory monitoring started. Warning: ${_warningThreshold}MB, Critical: ${_criticalThreshold}MB'); } /// 停止监控 void stopMonitoring() { WidgetsBinding.instance.removeObserver(this); _monitorTimer?.cancel(); _log.info('Memory monitoring stopped'); } /// 这是进程被杀前的最后一次清理机会 @override void didHaveMemoryPressure() { final now = DateTime.now(); // 防止频繁触发,增加冷却时间 if (_lastSystemPressureTime != null && now.difference(_lastSystemPressureTime!) < _systemPressureCooldown) { _log.info('System memory pressure ignored (cooldown)'); return; } _lastSystemPressureTime = now; _log.severe('!!! SYSTEM MEMORY PRESSURE: ${getCurrentMemoryMB().toStringAsFixed(1)}MB !!!'); _emergencyCleanup(reason: 'system_pressure'); _reportMemoryEvent('system_low_memory_signal', getCurrentMemoryMB()); } /// 动态计算阈值:防止在低端机上设置过高,或在高端机上太敏感 void _initializeDynamicThresholds() { if (Platform.isAndroid) { if (kDebugMode) { // Debug模式更保守,避免频繁清理 _warningThreshold = 400.0; _criticalThreshold = 500.0; } else { // Release模式预计内存减半 _warningThreshold = 120.0; _criticalThreshold = 160.0; } } else if (Platform.isIOS) { if (kDebugMode) { _warningThreshold = 300.0; _criticalThreshold = 400.0; } else { _warningThreshold = 150.0; _criticalThreshold = 200.0; } } else { _warningThreshold = 500.0; _criticalThreshold = 700.0; } } void _checkMemory() { if (!Platform.isAndroid && !Platform.isIOS) return; try { final memoryMB = getCurrentMemoryMB(); // 更新UI显示 memoryDisplay.value = 'Memory: ${memoryMB.toStringAsFixed(1)}MB'; // 只在超过warning时才记录,减少日志噪音 if (memoryMB > _warningThreshold) { _log.info('Memory: ${memoryMB.toStringAsFixed(1)} MB'); } if (memoryMB > _criticalThreshold) { _handleCriticalMemory(memoryMB); } else if (memoryMB > _warningThreshold) { _handleHighMemory(memoryMB); } else { _warningCount = 0; } } catch (e) { _log.warning('Memory check failed: $e'); } } void _handleCriticalMemory(double memoryMB) { _log.severe('CRITICAL memory usage: ${memoryMB.toStringAsFixed(1)} MB'); _warningCount++; _onCriticalMemory?.call(); _emergencyCleanup(reason: 'critical_threshold'); _reportMemoryEvent('critical_memory_usage', memoryMB); } void _handleHighMemory(double memoryMB) { _log.warning('HIGH memory usage: ${memoryMB.toStringAsFixed(1)} MB'); _warningCount++; _onHighMemory?.call(); _reportMemoryEvent('high_memory_usage', memoryMB); } /// 核心清理逻辑:物理释放显存和缓存 void _emergencyCleanup({String reason = 'unknown'}) { final beforeMB = getCurrentMemoryMB(); _log.warning('Emergency cleanup: ${beforeMB.toStringAsFixed(1)}MB ($reason)'); try { // 清理顺序很重要,先清理大头 Download().clearAllData(); PaintingBinding.instance.imageCache.clear(); PaintingBinding.instance.imageCache.clearLiveImages(); PaintingBinding.instance.handleMemoryPressure(); // 立即检查效果 final afterMB = getCurrentMemoryMB(); final freedMB = beforeMB - afterMB; _log.info('Cleanup result: ${afterMB.toStringAsFixed(1)}MB (${freedMB > 0 ? "freed" : "increased"}: ${freedMB.abs().toStringAsFixed(1)}MB)'); } catch (e) { _log.severe('Emergency cleanup failed: $e'); } } void _reportMemoryEvent(String eventName, double memoryMB) { if (kReleaseMode) { FirebaseHelper.logEvent(eventName, {'memory_mb': memoryMB.round(), 'warning_count': _warningCount, 'threshold_c': _criticalThreshold.round()}); } } static double getCurrentMemoryMB() { try { // RSS 包含代码段、栈、堆以及共享库。 // 在三星等低端机上,这是判断 OOM 最直接的指标。 return ProcessInfo.currentRss / (1024 * 1024); } catch (e) { return 0; } } /// 供外部在关键节点(如播广告前)手动清理 void manualCleanup() { _emergencyCleanup(reason: 'manual_call'); } static void logMemoryUsage(String label) { final memoryMB = getCurrentMemoryMB(); memoryDisplay.value = '[$label] ${memoryMB.toStringAsFixed(1)}MB'; _log.info('[$label] RSS Memory: ${memoryMB.toStringAsFixed(1)} MB'); } /// 获取内存显示组件(供Release模式使用) static Widget getMemoryWidget() { return ValueListenableBuilder( valueListenable: memoryDisplay, builder: (context, value, child) { return Container( padding: EdgeInsets.all(4), decoration: BoxDecoration( color: Colors.black54, borderRadius: BorderRadius.circular(4), ), child: Text( value, style: TextStyle(color: Colors.white, fontSize: 12), ), ); }, ); } }