| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- // 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';
- import '../config/config.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<String> memoryDisplay = ValueNotifier<String>('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() {
- if (!Config.isDebug) return;
- _emergencyCleanup(reason: 'manual_call');
- }
- static void logMemoryUsage(String label) {
- if (!Config.isDebug) return;
- 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<String>(
- 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)),
- );
- },
- );
- }
- }
|