From 3efbd47ffd94119793fa13dfc8ee08a4381ec831 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 9 Jul 2025 08:04:10 +0000 Subject: [PATCH] Add comprehensive memory analysis tool with guide and test script Co-authored-by: jxxghp --- MEMORY_ANALYSIS_GUIDE.md | 269 +++++++++++++++++++++++++++++++++++++++ app/helper/memory.py | 3 - test_memory_analysis.py | 131 +++++++++++++++++++ 3 files changed, 400 insertions(+), 3 deletions(-) create mode 100644 MEMORY_ANALYSIS_GUIDE.md create mode 100644 test_memory_analysis.py diff --git a/MEMORY_ANALYSIS_GUIDE.md b/MEMORY_ANALYSIS_GUIDE.md new file mode 100644 index 00000000..43457db2 --- /dev/null +++ b/MEMORY_ANALYSIS_GUIDE.md @@ -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() +``` + +这个工具将帮助你全面了解应用程序的内存使用情况,特别是找出那些"消失"的内存去向。 \ No newline at end of file diff --git a/app/helper/memory.py b/app/helper/memory.py index 7cb0d76c..bdf01596 100644 --- a/app/helper/memory.py +++ b/app/helper/memory.py @@ -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') diff --git a/test_memory_analysis.py b/test_memory_analysis.py new file mode 100644 index 00000000..77322c3d --- /dev/null +++ b/test_memory_analysis.py @@ -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() \ No newline at end of file