Files
xyzw_web_helper/MD说明文件夹/P4-内存监控机制详细说明.md
2025-10-17 20:56:50 +08:00

10 KiB
Raw Blame History

P4内存监控机制详细说明

一、核心功能

实时监控JavaScript内存使用情况在内存压力过大时自动触发清理防止

  • 浏览器卡顿、冻结
  • "页面无响应"提示
  • 标签页崩溃Aw, Snap!
  • 内存泄漏导致的性能下降

二、实现原理

1. 浏览器内存API

if (performance.memory) {
  const memory = {
    used: performance.memory.usedJSHeapSize,    // 已使用的JS堆字节
    total: performance.memory.totalJSHeapSize,  // 当前分配的JS堆
    limit: performance.memory.jsHeapSizeLimit   // JS堆上限通常2GB
  }
}

注意

  • Chrome/Edge支持
  • Firefox/Safari不支持会优雅降级不影响功能

2. 监控策略

检查频率每30秒一次不影响性能

三级预警机制

内存使用率 级别 触发动作 影响
< 70% 🟢 正常 无操作
70-85% 🟡 警告 标准清理 轻微,几乎无感知
> 85% 🔴 危险 紧急清理 中等,可能短暂卡顿

3. 清理动作详解

🟡 标准清理70-85%

触发条件内存使用率超过70%

清理动作

// 1. 清理已完成的任务进度数据
forceCleanupTaskProgress()
// - 删除 status='completed' 的进度对象
// - 释放 result 对象引用

// 2. 清理UI更新队列
clearPendingUIUpdates()
// - 清空 pendingUIUpdates Map
// - 取消待处理的定时器

预期效果

  • 释放约 20-40MB 内存100个Token场景
  • 用户无感知,不影响任何功能
  • 控制台输出警告日志

🔴 紧急清理(>85%

触发条件内存使用率超过85%

清理动作

// 1. 执行标准清理
forceCleanupTaskProgress()
clearPendingUIUpdates()

// 2. 删除所有任务的详细result数据
Object.keys(taskProgress.value).forEach(tokenId => {
  const progress = taskProgress.value[tokenId]
  if (progress.result) {
    delete progress.result  // 删除详细结果,保留状态
  }
})

// 3. 手动触发响应式更新
triggerRef(taskProgress)

// 4. 建议浏览器执行垃圾回收(如果支持)
if (window.gc) window.gc()

预期效果

  • 释放约 100-200MB 内存100个Token场景
  • 用户轻微感知可能短暂卡顿0.5-1秒
  • 影响:任务详情弹窗中的数据会丢失
  • 控制台输出错误日志

三、完整代码实现

/**
 * 获取当前内存使用情况MB
 * @returns {Object|null} { used, total, limit } 或 null不支持的浏览器
 */
const getMemoryUsage = () => {
  if (!performance.memory) {
    return null  // Firefox/Safari等浏览器不支持
  }
  
  return {
    used: Math.round(performance.memory.usedJSHeapSize / 1048576),   // MB
    total: Math.round(performance.memory.totalJSHeapSize / 1048576), // MB
    limit: Math.round(performance.memory.jsHeapSizeLimit / 1048576)  // MB
  }
}

/**
 * 监控内存使用,超限时自动清理
 */
const monitorMemoryUsage = () => {
  if (!isExecuting.value) return
  
  const memory = getMemoryUsage()
  if (!memory) return  // 浏览器不支持,直接返回
  
  const usagePercent = (memory.used / memory.limit) * 100
  
  // 🟡 警告级别内存使用超过70%
  if (usagePercent > 70 && usagePercent <= 85) {
    console.warn(
      `⚠️ [内存监控] 内存使用率: ${usagePercent.toFixed(1)}% ` +
      `(${memory.used}MB / ${memory.limit}MB) - 触发标准清理`
    )
    
    // 执行标准清理
    forceCleanupTaskProgress()
    clearPendingUIUpdates()
  }
  
  // 🔴 危险级别内存使用超过85%
  if (usagePercent > 85) {
    console.error(
      `🚨 [内存监控] 内存使用率危险: ${usagePercent.toFixed(1)}% ` +
      `(${memory.used}MB / ${memory.limit}MB) - 触发紧急清理`
    )
    
    // 执行标准清理
    forceCleanupTaskProgress()
    clearPendingUIUpdates()
    
    // 🔥 紧急措施删除所有任务的详细result数据
    let deletedCount = 0
    Object.keys(taskProgress.value).forEach(tokenId => {
      const progress = taskProgress.value[tokenId]
      if (progress && progress.result) {
        delete progress.result
        deletedCount++
      }
    })
    
    if (deletedCount > 0) {
      triggerRef(taskProgress)
      console.error(`🗑️ [紧急清理] 已删除 ${deletedCount} 个Token的详细结果数据`)
    }
    
    // 建议垃圾回收Chrome需要启动参数 --expose-gc
    if (typeof window !== 'undefined' && window.gc) {
      window.gc()
      console.warn('♻️ [紧急清理] 已触发强制垃圾回收')
    }
  }
}

/**
 * 启动内存监控定时器每30秒检查一次
 */
let memoryMonitorTimer = null

const startMemoryMonitor = () => {
  if (memoryMonitorTimer) return  // 已启动,避免重复
  
  // 立即执行一次检查
  monitorMemoryUsage()
  
  // 每30秒检查一次
  memoryMonitorTimer = setInterval(() => {
    monitorMemoryUsage()
  }, 30000)
  
  if (logConfig.value.batch) {
    console.log('🔄 [内存监控] 已启动每30秒检查一次')
  }
}

/**
 * 停止内存监控
 */
const stopMemoryMonitor = () => {
  if (memoryMonitorTimer) {
    clearInterval(memoryMonitorTimer)
    memoryMonitorTimer = null
    
    if (logConfig.value.batch) {
      console.log('⏹️ [内存监控] 已停止')
    }
  }
}

四、集成到批量任务

在 startBatchExecution 开始时启动

const startBatchExecution = async (...) => {
  // ... 现有代码 ...
  
  // 🔥 启动内存监控
  startMemoryMonitor()
  
  // 执行批量任务...
}

在 completeBatchExecution 结束时停止

const completeBatchExecution = () => {
  // ... 现有清理代码 ...
  
  // 🔥 停止内存监控
  stopMemoryMonitor()
}

五、优缺点分析

优点

  1. 自动保护

    • 无需用户干预
    • 自动检测并清理
    • 防止浏览器崩溃
  2. 三级预警

    • 渐进式清理策略
    • 最小化对用户体验的影响
    • 只在必要时触发紧急清理
  3. 性能开销极小

    • 每30秒仅1次检查
    • 检查本身几乎无开销(< 1ms
    • 不影响任务执行速度
  4. 调试友好

    • 控制台输出详细日志
    • 可以看到内存使用趋势
    • 方便排查内存问题

⚠️ 缺点

  1. 浏览器兼容性

    • Firefox/Safari不支持 performance.memory
    • 但会优雅降级,不影响功能
  2. 紧急清理影响

    • 删除详细result数据后任务详情弹窗会显示"暂无数据"
    • 但这只在内存极度紧张时发生(>85%
    • 实际场景中很少触发
  3. 误判可能

    • 如果其他标签页占用大量内存,也可能触发清理
    • 但清理动作本身是无害的

六、实际场景测试

场景1正常运行100个Token

[内存监控] 已启动
[内存监控] 内存使用率: 45.2% (924MB / 2048MB) - 正常
[内存监控] 内存使用率: 52.8% (1081MB / 2048MB) - 正常
[内存监控] 内存使用率: 58.3% (1194MB / 2048MB) - 正常

结论:不触发任何清理,正常运行

场景2高内存压力500个Token

[内存监控] 已启动
[内存监控] 内存使用率: 65.4% (1339MB / 2048MB) - 正常
⚠️ [内存监控] 内存使用率: 72.1% (1477MB / 2048MB) - 触发标准清理
✅ [强制清理] 清理了 150 个已完成任务的进度数据
[内存监控] 内存使用率: 68.9% (1411MB / 2048MB) - 正常

结论:触发标准清理,成功释放内存

场景3极限压力1000个Token + 其他页面占用)

[内存监控] 已启动
[内存监控] 内存使用率: 78.5% (1608MB / 2048MB) - 正常
⚠️ [内存监控] 内存使用率: 81.2% (1663MB / 2048MB) - 触发标准清理
⚠️ [内存监控] 内存使用率: 87.4% (1790MB / 2048MB) - 触发紧急清理
🗑️ [紧急清理] 已删除 800 个Token的详细结果数据
♻️ [紧急清理] 已触发强制垃圾回收
[内存监控] 内存使用率: 65.8% (1348MB / 2048MB) - 正常

结论紧急清理成功避免崩溃释放约440MB内存

七、是否需要实施?

📊 推荐指数: (3/5)

适合场景

强烈推荐

  • 经常执行200+个Token的批量任务
  • 用户反馈过浏览器卡顿或崩溃
  • 追求极致稳定性

⚠️ 可选

  • 主要执行10-100个Token内存压力小
  • 对代码简洁性有要求
  • 不想增加监控开销

不推荐

  • 只执行少量Token< 10个
  • 内存充足16GB+)且只开一个标签页

决策建议

我的建议

  1. 如果用户规模未知建议实施

    • 作为一个"保险机制"
    • 几乎无成本,但能避免极端情况
  2. 如果明确用户场景根据规模决定

    • 10-100个Token可不实施
    • 200+个Token建议实施
    • 500+个Token强烈建议实施
  3. 开发阶段建议实施

    • 帮助发现内存泄漏
    • 查看内存使用趋势
    • 优化清理策略

八、轻量级替代方案

如果觉得完整的P4过于复杂可以考虑简化版

简化版:只在任务结束时检查

const completeBatchExecution = () => {
  // 任务结束时检查一次内存
  const memory = getMemoryUsage()
  if (memory && memory.used / memory.limit > 0.7) {
    console.warn(`⚠️ 内存使用率较高: ${((memory.used / memory.limit) * 100).toFixed(1)}%`)
    forceCleanupTaskProgress()
  }
  
  // ... 其他清理代码
}

优点

  • 代码极简5行
  • 无定时器开销
  • 仍能提供基本保护

缺点

  • 只在任务结束时清理
  • 无法在执行过程中防护

九、总结

P4内存监控机制是一个可选的"安全气囊"功能:

特性 评价
必要性 中等
实施难度 简单
性能开销 极低
代码复杂度 中等
用户体验影响 极低(正常情况无影响)
稳定性提升 显著(极端场景)

最终建议

  • 如果追求极致稳定性 → 实施完整版
  • 如果追求代码简洁 → 实施简化版或不实施
  • 如果追求平衡 → 实施简化版

您可以根据实际用户反馈决定

  • 如果从未出现内存问题 → 暂不实施
  • 如果偶尔有用户反馈卡顿 → 实施简化版
  • 如果频繁出现崩溃 → 实施完整版