Files
TrueGrowth/docs/MEMORY_OPTIMIZATION.md

216 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 内存优化分析与修复方案
## 问题分析
基于 `/sw-debug.html` 的内存日志分析,发现以下问题:
### 内存使用情况
| 指标 | 值 | 问题 |
|------|-----|------|
| 已使用内存 | 3.3-4.3 GB | 🔴 极高 |
| 内存上限 | 4 GB | 接近/超过上限 |
| 使用率 | 77-101% | 🔴 危险区域 |
| 图片数量 | 30 | 可能过多 |
| 视频数量 | 1 | - |
| Plait 元素 | 80 | 正常 |
### 关键发现
1. **启动时就有 ~3.5GB 内存** - 说明不是运行时泄漏,而是初始加载问题
2. **长任务期间内存飙升到 4.3GB** - 超过了 4GB 限制
3. **刷新后内存不降反升** - 每次刷新内存都在增长
## 问题根源
### 1. 高分辨率图片解码 (主要问题)
**问题描述**
- 30 张图片在画布上全部解码到内存中
- 一张 4K 图片 (4096x2160) 解码后约 35MB
- 30 张高分辨率图片可能占用 300-1000MB
**代码位置**
- `packages/drawnix/src/plugins/with-image.tsx`
- Plait 框架内部的图片渲染
### 2. 聊天附件 Base64 存储 (中等问题)
**问题描述**
- 聊天消息的附件以 base64 字符串形式存储在 IndexedDB
- 一张 2MB 的图片转为 base64 后约 2.6MB
- 大量附件累积会占用大量存储和内存
**代码位置**
```typescript
// packages/drawnix/src/types/chat.types.ts
export interface Attachment {
data: string; // Base64 编码,可能非常大
}
```
### 3. 任务数据累积
**问题描述**
- 已完成的任务永久保存在 IndexedDB
- 任务结果包含 URL 引用,但工作流数据可能较大
**代码位置**
- `apps/web/src/sw/task-queue/storage.ts`
### 4. 视频解码缓冲区
**问题描述**
- 视频元素的解码缓冲区占用内存
- 即使视频暂停,缓冲区也可能保留
## 已实施的修复
### 1. 内存监控服务
添加了 `memory-monitor-service.ts`
```typescript
// packages/drawnix/src/services/memory-monitor-service.ts
// 功能:
// - 周期性检查内存使用(每 30 秒)
// - 在内存压力过大时触发清理75% 阈值)
// - 支持注册自定义清理处理器
// - 提供内存统计 API
// 使用:
import { memoryMonitorService } from './services/memory-monitor-service';
// 获取内存状态
const stats = memoryMonitorService.getMemoryStats();
console.log(stats?.formatted.used); // "3.2 GB"
// 手动触发清理
await memoryMonitorService.triggerCleanup();
```
### 2. 自动启动内存监控
`apps/web/src/main.tsx` 中添加了自动启动:
```typescript
import { memoryMonitorService } from '../../../packages/drawnix/src/services/memory-monitor-service';
// 延迟 5 秒启动,避免影响首屏加载
setTimeout(() => {
memoryMonitorService.start();
memoryMonitorService.logMemoryStatus();
}, 5000);
```
### 3. 离屏图片自动卸载
内存监控服务包含了离屏图片清理逻辑:
```typescript
// 找到离屏图片并暂时移除 src
const isOffscreen =
rect.bottom < -500 ||
rect.top > window.innerHeight + 500;
if (isOffscreen) {
img.setAttribute('data-lazy-src', src);
img.removeAttribute('src');
}
```
## 建议的进一步优化
### 优先级 1图片懒加载优化
**目标**:只解码视口内的图片
**方案**
1. 在 Plait 的图片渲染中使用 `loading="lazy"``decoding="async"`
2. 对离屏图片使用占位符而不是实际图片
**修改位置**
- `packages/drawnix/src/plugins/with-image.tsx`
### 优先级 2聊天附件外部化存储
**目标**:减少 IndexedDB 中的 base64 数据
**方案**
1. 将附件 Blob 存储到 Cache API
2. 在 IndexedDB 中只存储虚拟 URL 引用
3. 需要时从 Cache API 获取
**修改位置**
- `packages/drawnix/src/services/chat-storage-service.ts`
- `packages/drawnix/src/types/chat.types.ts`
### 优先级 3图片尺寸限制
**目标**:限制画布上图片的最大解码尺寸
**方案**
1. 在插入图片时检查尺寸
2. 对超大图片自动缩放
3. 提供高清预览选项
### 优先级 4定期内存报告
**目标**:帮助用户了解内存使用情况
**方案**
1. 在设置页面显示内存使用统计
2. 在内存压力时显示警告
3. 提供手动清理选项
## 用户操作建议
如果遇到内存问题,可以:
1. **减少画布上的图片数量** - 将不需要的图片移到其他画板
2. **使用较低分辨率的图片** - 特别是在移动设备上
3. **定期刷新页面** - 释放累积的内存
4. **清理聊天历史** - 删除包含大量附件的旧会话
5. **关闭其他标签页** - 释放浏览器资源
## 调试方法
### 使用 SW Debug 面板
访问 `/sw-debug.html` 查看:
- 内存使用趋势
- 长任务监控
- 内存快照
### 使用 Chrome DevTools
1. **Memory 面板**
- 拍摄堆快照分析内存分布
- 查看哪些对象占用最多内存
2. **Performance 面板**
- 记录性能profile
- 分析长任务和内存增长
### 控制台命令
```javascript
// 获取内存状态
memoryMonitorService.logMemoryStatus();
// 手动触发清理
await memoryMonitorService.triggerCleanup(true);
// 获取详细统计
const stats = memoryMonitorService.getMemoryStats();
console.table(stats);
```
## 相关文件
- `packages/drawnix/src/services/memory-monitor-service.ts` - 内存监控服务
- `apps/web/src/main.tsx` - 内存监控初始化
- `packages/drawnix/src/components/lazy-image/LazyImage.tsx` - 懒加载图片组件
- `packages/drawnix/src/hooks/useImageLazyLoad.ts` - 图片懒加载 Hook