mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-02-13 07:25:53 +08:00
Add comprehensive memory analysis tool with guide and test script
Co-authored-by: jxxghp <jxxghp@163.com>
This commit is contained in:
269
MEMORY_ANALYSIS_GUIDE.md
Normal file
269
MEMORY_ANALYSIS_GUIDE.md
Normal file
@@ -0,0 +1,269 @@
|
||||
# 内存分析工具使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
这个增强版的内存分析工具专门用于诊断Python应用程序的内存问题,特别是解决"总内存比各对象占比内存大很多"的问题。
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 系统级内存分析
|
||||
- 进程内存使用详情(RSS、VMS、共享内存等)
|
||||
- 系统内存状态
|
||||
- 内存映射分析
|
||||
|
||||
### 2. Python对象深度分析
|
||||
- 对象类型统计(按内存大小排序)
|
||||
- Python对象总内存计算
|
||||
- 未统计内存识别
|
||||
|
||||
### 3. 内存映射详细分析
|
||||
- 按权限分类的内存映射
|
||||
- 按文件分类的内存映射
|
||||
- 识别C扩展和系统库占用的内存
|
||||
|
||||
### 4. 大对象分析
|
||||
- 识别大于1MB的对象
|
||||
- 对象详细信息(类型、大小、内容预览)
|
||||
|
||||
### 5. 内存泄漏检测
|
||||
- tracemalloc内存分配统计
|
||||
- 内存分配最多的位置
|
||||
- 垃圾回收统计
|
||||
- 不可达对象检测
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基本使用
|
||||
|
||||
```python
|
||||
from app.helper.memory import MemoryHelper
|
||||
|
||||
# 创建内存分析器实例
|
||||
memory_helper = MemoryHelper()
|
||||
|
||||
# 获取内存摘要
|
||||
summary = memory_helper.get_memory_summary()
|
||||
print(f"总内存: {summary['total_memory_mb']:.2f} MB")
|
||||
print(f"Python对象: {summary['python_objects_mb']:.2f} MB")
|
||||
print(f"未统计内存: {summary['unaccounted_mb']:.2f} MB")
|
||||
|
||||
# 强制垃圾回收
|
||||
collected = memory_helper.force_garbage_collection()
|
||||
print(f"清理了 {collected} 个对象")
|
||||
|
||||
# 创建详细分析报告
|
||||
analysis_file = memory_helper.create_detailed_memory_analysis()
|
||||
print(f"详细报告已保存到: {analysis_file}")
|
||||
```
|
||||
|
||||
### 内存增长分析
|
||||
|
||||
```python
|
||||
# 分析内存增长趋势(5分钟间隔)
|
||||
growth_info = memory_helper.analyze_memory_growth(300)
|
||||
print(f"内存增长率: {growth_info['growth_rate_mb_per_hour']:.2f} MB/小时")
|
||||
```
|
||||
|
||||
### 启动自动监控
|
||||
|
||||
```python
|
||||
# 启动内存监控(需要配置MEMORY_ANALYSIS=True)
|
||||
memory_helper.start_monitoring()
|
||||
|
||||
# 停止监控
|
||||
memory_helper.stop_monitoring()
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
在配置文件中设置以下选项:
|
||||
|
||||
```python
|
||||
# 启用内存分析
|
||||
MEMORY_ANALYSIS = True
|
||||
|
||||
# 内存快照间隔(分钟)
|
||||
MEMORY_SNAPSHOT_INTERVAL = 5
|
||||
|
||||
# 保留的快照文件数量
|
||||
MEMORY_SNAPSHOT_KEEP_COUNT = 30
|
||||
```
|
||||
|
||||
## 输出文件
|
||||
|
||||
### 1. 内存快照文件
|
||||
- 位置: `logs/memory_snapshots/memory_snapshot_YYYYMMDD_HHMMSS.txt`
|
||||
- 内容: 基本的内存使用统计
|
||||
|
||||
### 2. 详细分析报告
|
||||
- 位置: `logs/memory_snapshots/detailed_memory_analysis_YYYYMMDD_HHMMSS.txt`
|
||||
- 内容: 完整的内存分析报告
|
||||
|
||||
## 解决内存问题的步骤
|
||||
|
||||
### 1. 识别未统计内存
|
||||
```python
|
||||
summary = memory_helper.get_memory_summary()
|
||||
if summary['unaccounted_percent'] > 50:
|
||||
print("警告: 超过50%的内存未被Python对象统计")
|
||||
print("可能的原因: C扩展、系统缓存、内存碎片")
|
||||
```
|
||||
|
||||
### 2. 分析内存映射
|
||||
详细分析报告中的"内存映射详细分析"部分会显示:
|
||||
- 哪些文件占用了大量内存
|
||||
- 内存权限分布
|
||||
- 识别C扩展库
|
||||
|
||||
### 3. 检测内存泄漏
|
||||
```python
|
||||
# 定期检查内存增长
|
||||
growth_info = memory_helper.analyze_memory_growth(300)
|
||||
if growth_info['growth_rate_mb_per_hour'] > 100:
|
||||
print("警告: 内存增长过快,可能存在内存泄漏")
|
||||
```
|
||||
|
||||
### 4. 分析大对象
|
||||
详细分析报告会列出所有大于1MB的对象,帮助识别:
|
||||
- 意外的内存占用
|
||||
- 缓存未清理
|
||||
- 数据结构过大
|
||||
|
||||
## 常见问题解决
|
||||
|
||||
### 问题1: 总内存比Python对象内存大很多
|
||||
|
||||
**原因**:
|
||||
- C扩展库占用内存
|
||||
- 系统缓存
|
||||
- 内存碎片
|
||||
- 共享库
|
||||
|
||||
**解决方法**:
|
||||
1. 查看内存映射分析
|
||||
2. 检查是否有大量C扩展
|
||||
3. 分析系统级内存使用
|
||||
|
||||
### 问题2: 内存持续增长
|
||||
|
||||
**原因**:
|
||||
- 内存泄漏
|
||||
- 缓存未清理
|
||||
- 循环引用
|
||||
|
||||
**解决方法**:
|
||||
1. 使用tracemalloc分析内存分配
|
||||
2. 检查垃圾回收统计
|
||||
3. 分析大对象列表
|
||||
|
||||
### 问题3: 特定对象类型占用过多内存
|
||||
|
||||
**解决方法**:
|
||||
1. 查看对象类型统计
|
||||
2. 分析大对象详情
|
||||
3. 检查对象引用关系
|
||||
|
||||
## 性能注意事项
|
||||
|
||||
1. **详细分析耗时**: `create_detailed_memory_analysis()` 可能需要几秒到几分钟
|
||||
2. **内存开销**: 分析过程本身会消耗一些内存
|
||||
3. **建议频率**: 不要过于频繁地运行详细分析,建议间隔5分钟以上
|
||||
|
||||
## 调试技巧
|
||||
|
||||
### 1. 在关键点添加内存检查
|
||||
```python
|
||||
def critical_function():
|
||||
memory_helper = MemoryHelper()
|
||||
before = memory_helper.get_memory_summary()
|
||||
|
||||
# 执行关键操作
|
||||
do_something()
|
||||
|
||||
after = memory_helper.get_memory_summary()
|
||||
growth = after['total_memory_mb'] - before['total_memory_mb']
|
||||
if growth > 10:
|
||||
print(f"警告: 函数执行后内存增长 {growth:.2f} MB")
|
||||
```
|
||||
|
||||
### 2. 监控特定操作
|
||||
```python
|
||||
def monitor_operation(operation_name):
|
||||
memory_helper = MemoryHelper()
|
||||
before = memory_helper.get_memory_summary()
|
||||
|
||||
# 执行操作
|
||||
result = perform_operation()
|
||||
|
||||
after = memory_helper.get_memory_summary()
|
||||
growth = after['total_memory_mb'] - before['total_memory_mb']
|
||||
|
||||
logger.info(f"{operation_name}: 内存增长 {growth:.2f} MB")
|
||||
return result
|
||||
```
|
||||
|
||||
## 示例输出
|
||||
|
||||
### 内存摘要示例
|
||||
```
|
||||
total_memory_mb: 708.20
|
||||
python_objects_mb: 130.45
|
||||
unaccounted_mb: 577.75
|
||||
unaccounted_percent: 81.6
|
||||
```
|
||||
|
||||
### 详细分析报告结构
|
||||
```
|
||||
详细内存分析报告 - 2025-07-09 14:26:00
|
||||
====================================================================================================
|
||||
|
||||
1. 系统级内存分析
|
||||
--------------------------------------------------
|
||||
进程ID: 12345
|
||||
进程名称: python
|
||||
内存使用详情:
|
||||
RSS (物理内存): 708.20 MB
|
||||
VMS (虚拟内存): 1024.50 MB
|
||||
共享内存: 45.30 MB
|
||||
...
|
||||
|
||||
2. Python对象深度分析
|
||||
--------------------------------------------------
|
||||
总对象数: 1,234,567
|
||||
对象类型统计 (按内存大小排序):
|
||||
类型 数量 总大小(MB) 平均大小(B)
|
||||
str 318,537 34.56 113.5
|
||||
dict 101,049 32.23 319.2
|
||||
...
|
||||
|
||||
3. 内存映射详细分析
|
||||
--------------------------------------------------
|
||||
按权限分类的内存映射:
|
||||
权限 数量 大小(MB)
|
||||
r-xp 45 156.78
|
||||
rw-p 23 89.45
|
||||
...
|
||||
|
||||
4. 大对象详细分析
|
||||
--------------------------------------------------
|
||||
大对象 (>1MB) 数量: 15
|
||||
|
||||
1. dict - 45.67 MB
|
||||
字典项数: 125000
|
||||
示例键: ['user_data', 'cache', 'config']
|
||||
|
||||
2. list - 23.45 MB
|
||||
元素数量: 500000
|
||||
|
||||
5. 内存泄漏检测
|
||||
--------------------------------------------------
|
||||
tracemalloc当前内存: 125.67 MB
|
||||
tracemalloc峰值内存: 145.23 MB
|
||||
|
||||
内存分配最多的位置 (前15个):
|
||||
1. 1250 个对象, 45.67 MB
|
||||
File "/app/core/cache.py", line 123
|
||||
cache_data = load_large_dataset()
|
||||
```
|
||||
|
||||
这个工具将帮助你全面了解应用程序的内存使用情况,特别是找出那些"消失"的内存去向。
|
||||
@@ -289,9 +289,6 @@ class MemoryHelper(metaclass=Singleton):
|
||||
|
||||
# 获取内存分配统计
|
||||
try:
|
||||
stats = tracemalloc.get_traced_memory()
|
||||
f.write(f"内存分配统计: {stats}\n")
|
||||
|
||||
# 获取前10个内存分配最多的位置
|
||||
snapshot = tracemalloc.take_snapshot()
|
||||
top_stats = snapshot.statistics('lineno')
|
||||
|
||||
131
test_memory_analysis.py
Normal file
131
test_memory_analysis.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
内存分析工具测试脚本
|
||||
用于验证内存分析工具的功能和修复后的效果
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import gc
|
||||
|
||||
# 添加项目路径
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'app'))
|
||||
|
||||
from app.helper.memory import MemoryHelper
|
||||
from app.log import logger
|
||||
|
||||
def test_memory_analysis():
|
||||
"""测试内存分析功能"""
|
||||
print("开始测试内存分析工具...")
|
||||
|
||||
# 创建内存分析器实例
|
||||
memory_helper = MemoryHelper()
|
||||
|
||||
# 1. 测试内存摘要
|
||||
print("\n1. 测试内存摘要:")
|
||||
summary = memory_helper.get_memory_summary()
|
||||
for key, value in summary.items():
|
||||
print(f" {key}: {value:.2f}")
|
||||
|
||||
# 2. 测试强制垃圾回收
|
||||
print("\n2. 测试强制垃圾回收:")
|
||||
collected = memory_helper.force_garbage_collection()
|
||||
print(f" 清理了 {collected} 个对象")
|
||||
|
||||
# 3. 创建一些测试数据来模拟内存使用
|
||||
print("\n3. 创建测试数据:")
|
||||
test_data = {
|
||||
'large_list': [i for i in range(100000)], # 约2.4MB
|
||||
'large_dict': {f'key_{i}': f'value_{i}' for i in range(50000)}, # 约3MB
|
||||
'large_string': 'x' * 1000000, # 约1MB
|
||||
}
|
||||
print(f" 创建了测试数据,包含 {len(test_data)} 个大对象")
|
||||
|
||||
# 4. 再次获取内存摘要
|
||||
print("\n4. 创建测试数据后的内存摘要:")
|
||||
summary_after = memory_helper.get_memory_summary()
|
||||
for key, value in summary_after.items():
|
||||
print(f" {key}: {value:.2f}")
|
||||
|
||||
# 5. 计算内存增长
|
||||
print("\n5. 内存增长分析:")
|
||||
if summary and summary_after:
|
||||
total_growth = summary_after['total_memory_mb'] - summary['total_memory_mb']
|
||||
python_growth = summary_after['python_objects_mb'] - summary['python_objects_mb']
|
||||
unaccounted_growth = summary_after['unaccounted_mb'] - summary['unaccounted_mb']
|
||||
|
||||
print(f" 总内存增长: {total_growth:.2f} MB")
|
||||
print(f" Python对象增长: {python_growth:.2f} MB")
|
||||
print(f" 未统计内存增长: {unaccounted_growth:.2f} MB")
|
||||
|
||||
# 6. 创建详细分析报告
|
||||
print("\n6. 创建详细分析报告:")
|
||||
analysis_file = memory_helper.create_detailed_memory_analysis()
|
||||
if analysis_file:
|
||||
print(f" 详细分析报告已保存到: {analysis_file}")
|
||||
|
||||
# 显示报告的前几行
|
||||
print("\n 报告预览:")
|
||||
try:
|
||||
with open(analysis_file, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()[:20]
|
||||
for line in lines:
|
||||
print(f" {line.rstrip()}")
|
||||
print(" ...")
|
||||
except Exception as e:
|
||||
print(f" 读取报告失败: {e}")
|
||||
|
||||
# 7. 清理测试数据
|
||||
print("\n7. 清理测试数据:")
|
||||
del test_data
|
||||
collected = memory_helper.force_garbage_collection()
|
||||
print(f" 清理了 {collected} 个对象")
|
||||
|
||||
# 8. 最终内存摘要
|
||||
print("\n8. 清理后的内存摘要:")
|
||||
final_summary = memory_helper.get_memory_summary()
|
||||
for key, value in final_summary.items():
|
||||
print(f" {key}: {value:.2f}")
|
||||
|
||||
print("\n内存分析工具测试完成!")
|
||||
|
||||
def test_memory_growth_detection():
|
||||
"""测试内存增长检测功能"""
|
||||
print("\n开始测试内存增长检测...")
|
||||
|
||||
memory_helper = MemoryHelper()
|
||||
|
||||
# 获取初始内存
|
||||
initial_summary = memory_helper.get_memory_summary()
|
||||
print(f"初始内存: {initial_summary.get('total_memory_mb', 0):.2f} MB")
|
||||
|
||||
# 创建一些数据
|
||||
data_list = []
|
||||
for i in range(10):
|
||||
data_list.append([j for j in range(10000)]) # 每次约240KB
|
||||
time.sleep(0.1) # 短暂延迟
|
||||
|
||||
# 获取最终内存
|
||||
final_summary = memory_helper.get_memory_summary()
|
||||
print(f"最终内存: {final_summary.get('total_memory_mb', 0):.2f} MB")
|
||||
|
||||
# 计算增长
|
||||
if initial_summary and final_summary:
|
||||
growth = final_summary['total_memory_mb'] - initial_summary['total_memory_mb']
|
||||
print(f"内存增长: {growth:.2f} MB")
|
||||
|
||||
# 清理
|
||||
del data_list
|
||||
memory_helper.force_garbage_collection()
|
||||
|
||||
print("内存增长检测测试完成!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
test_memory_analysis()
|
||||
test_memory_growth_detection()
|
||||
except Exception as e:
|
||||
print(f"测试过程中出现错误: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
Reference in New Issue
Block a user