mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-04-24 10:42:48 +08:00
fix pympler
This commit is contained in:
@@ -127,9 +127,16 @@ class MemoryHelper(metaclass=Singleton):
|
||||
f.write("最大内存占用对象详情:\n")
|
||||
f.write("-" * 80 + "\n")
|
||||
|
||||
largest_objects = self._get_largest_objects()
|
||||
for i, obj_info in enumerate(largest_objects[:10], 1):
|
||||
f.write(f"{i:2d}. {obj_info['type']:<30} {obj_info['size_mb']:>8.2f} MB - {obj_info['description']}\n")
|
||||
try:
|
||||
largest_objects = self._get_largest_objects()
|
||||
if largest_objects:
|
||||
for i, obj_info in enumerate(largest_objects[:10], 1):
|
||||
f.write(f"{i:2d}. {obj_info['type']:<30} {obj_info['size_mb']:>8.2f} MB - {obj_info['description']}\n")
|
||||
else:
|
||||
f.write("未找到大于1KB的对象或分析失败\n")
|
||||
except Exception as e:
|
||||
f.write(f"大对象分析失败: {e}\n")
|
||||
logger.warning(f"大对象分析失败,但快照生成继续: {e}")
|
||||
|
||||
logger.info(f"内存快照已保存: {snapshot_file}, 当前内存使用: {memory_usage / 1024 / 1024:.2f} MB")
|
||||
|
||||
@@ -163,28 +170,51 @@ class MemoryHelper(metaclass=Singleton):
|
||||
try:
|
||||
# 获取所有对象
|
||||
all_objects = muppy.get_objects()
|
||||
logger.debug(f"开始分析 {len(all_objects)} 个对象")
|
||||
|
||||
# 计算每个对象的大小并收集信息
|
||||
object_sizes = []
|
||||
for obj in all_objects:
|
||||
failed_count = 0
|
||||
skip_modules = {'tkinter', 'matplotlib', 'PIL', 'cv2'} # 可能导致GUI库问题的模块
|
||||
|
||||
for i, obj in enumerate(all_objects):
|
||||
try:
|
||||
# 检查对象类型,跳过可能有问题的模块
|
||||
obj_module = getattr(type(obj), '__module__', '')
|
||||
if any(skip_mod in obj_module for skip_mod in skip_modules):
|
||||
continue
|
||||
|
||||
# 使用asizeof计算对象真实大小
|
||||
size = asizeof.asizeof(obj)
|
||||
if size > 1024: # 只关注大于1KB的对象
|
||||
obj_type = type(obj).__name__
|
||||
obj_module = getattr(type(obj), '__module__', 'unknown')
|
||||
|
||||
# 生成对象描述
|
||||
description = self._generate_object_description(obj)
|
||||
|
||||
object_sizes.append({
|
||||
'size': size,
|
||||
'type': f"{obj_module}.{obj_type}" if obj_module != 'builtins' else obj_type,
|
||||
'type': f"{obj_module}.{obj_type}" if obj_module and obj_module != 'builtins' else obj_type,
|
||||
'description': description
|
||||
})
|
||||
except (TypeError, AttributeError, RuntimeError):
|
||||
# 某些对象可能无法计算大小,跳过
|
||||
|
||||
except (TypeError, AttributeError, RuntimeError, OSError, ImportError) as e:
|
||||
# 扩展异常处理,包括共享库错误
|
||||
failed_count += 1
|
||||
if failed_count <= 5: # 只记录前几个错误,避免日志泛滥
|
||||
logger.debug(f"跳过对象分析 (第{i+1}个): {type(e).__name__}: {str(e)[:100]}")
|
||||
continue
|
||||
except Exception as e:
|
||||
# 处理其他未预期的异常
|
||||
failed_count += 1
|
||||
if failed_count <= 5:
|
||||
logger.debug(f"跳过对象分析 (第{i+1}个): 未知错误: {str(e)[:100]}")
|
||||
continue
|
||||
|
||||
if failed_count > 5:
|
||||
logger.debug(f"总共跳过了 {failed_count} 个无法分析的对象")
|
||||
|
||||
logger.debug(f"成功分析了 {len(object_sizes)} 个大对象")
|
||||
|
||||
# 按大小排序并取前N个
|
||||
object_sizes.sort(key=lambda x: x['size'], reverse=True)
|
||||
@@ -212,46 +242,88 @@ class MemoryHelper(metaclass=Singleton):
|
||||
:return: 对象描述字符串
|
||||
"""
|
||||
try:
|
||||
# 获取对象类型名称,避免访问可能有问题的属性
|
||||
obj_type_name = type(obj).__name__
|
||||
|
||||
# 根据对象类型生成不同的描述
|
||||
if isinstance(obj, (list, tuple)):
|
||||
length = len(obj)
|
||||
first_type = type(obj[0]).__name__ if obj else 'empty'
|
||||
return f"长度={length}, 示例元素类型={first_type}"
|
||||
try:
|
||||
length = len(obj)
|
||||
first_type = type(obj[0]).__name__ if obj else 'empty'
|
||||
return f"长度={length}, 示例元素类型={first_type}"
|
||||
except (IndexError, TypeError):
|
||||
return f"{obj_type_name}(长度未知)"
|
||||
|
||||
elif isinstance(obj, dict):
|
||||
length = len(obj)
|
||||
if obj:
|
||||
first_key = next(iter(obj))
|
||||
key_type = type(first_key).__name__
|
||||
return f"键值对数={length}, 示例键类型={key_type}"
|
||||
return f"键值对数={length}, 示例键类型=empty"
|
||||
try:
|
||||
length = len(obj)
|
||||
if obj:
|
||||
first_key = next(iter(obj))
|
||||
key_type = type(first_key).__name__
|
||||
return f"键值对数={length}, 示例键类型={key_type}"
|
||||
return f"键值对数={length}, 示例键类型=empty"
|
||||
except (StopIteration, TypeError):
|
||||
return f"{obj_type_name}(大小未知)"
|
||||
|
||||
elif isinstance(obj, set):
|
||||
length = len(obj)
|
||||
if obj:
|
||||
first_item = next(iter(obj))
|
||||
item_type = type(first_item).__name__
|
||||
return f"元素数={length}, 示例元素类型={item_type}"
|
||||
return f"元素数={length}, 示例元素类型=empty"
|
||||
try:
|
||||
length = len(obj)
|
||||
if obj:
|
||||
first_item = next(iter(obj))
|
||||
item_type = type(first_item).__name__
|
||||
return f"元素数={length}, 示例元素类型={item_type}"
|
||||
return f"元素数={length}, 示例元素类型=empty"
|
||||
except (StopIteration, TypeError):
|
||||
return f"{obj_type_name}(大小未知)"
|
||||
|
||||
elif isinstance(obj, str):
|
||||
length = len(obj)
|
||||
preview = obj[:50] + '...' if length > 50 else obj
|
||||
return f"长度={length}, 内容='{preview}'"
|
||||
try:
|
||||
length = len(obj)
|
||||
# 限制预览长度,避免显示问题字符
|
||||
safe_preview = ''.join(c for c in obj[:30] if c.isprintable())
|
||||
preview = safe_preview + '...' if length > 30 else safe_preview
|
||||
return f"长度={length}, 内容='{preview}'"
|
||||
except (UnicodeError, TypeError):
|
||||
return f"{obj_type_name}(字符串,长度未知)"
|
||||
|
||||
elif hasattr(obj, '__name__'):
|
||||
return f"名称={obj.__name__}"
|
||||
elif isinstance(obj, bytes):
|
||||
try:
|
||||
length = len(obj)
|
||||
return f"字节数据,长度={length}"
|
||||
except TypeError:
|
||||
return f"{obj_type_name}(字节数据,长度未知)"
|
||||
|
||||
elif hasattr(obj, '__dict__'):
|
||||
attrs_count = len(obj.__dict__)
|
||||
return f"实例属性数={attrs_count}"
|
||||
# 谨慎处理可能有问题的属性访问
|
||||
try:
|
||||
if hasattr(obj, '__name__') and callable(getattr(obj, '__name__', None)):
|
||||
name = str(obj.__name__)[:50]
|
||||
return f"名称={name}"
|
||||
except (AttributeError, TypeError, OSError):
|
||||
pass
|
||||
|
||||
else:
|
||||
try:
|
||||
if hasattr(obj, '__dict__'):
|
||||
attrs_count = len(obj.__dict__)
|
||||
return f"实例属性数={attrs_count}"
|
||||
except (AttributeError, TypeError, OSError):
|
||||
pass
|
||||
|
||||
# 最后的安全转换
|
||||
try:
|
||||
obj_str = str(obj)[:50]
|
||||
return f"对象={obj_str}"
|
||||
# 确保字符串是可打印的
|
||||
safe_str = ''.join(c for c in obj_str if c.isprintable())
|
||||
return f"对象={safe_str}" if safe_str else f"{obj_type_name}对象"
|
||||
except (UnicodeError, TypeError, OSError):
|
||||
return f"{obj_type_name}对象"
|
||||
|
||||
except Exception as e:
|
||||
return f"无法获取描述:{e}"
|
||||
# 最后的异常处理,确保总是返回有用信息
|
||||
try:
|
||||
obj_type_name = type(obj).__name__
|
||||
return f"{obj_type_name}(描述生成失败):{e}"
|
||||
except Exception as e:
|
||||
return f"未知对象(描述生成失败):{e}"
|
||||
|
||||
def get_current_memory_info(self) -> dict:
|
||||
"""
|
||||
@@ -305,7 +377,11 @@ class MemoryHelper(metaclass=Singleton):
|
||||
break
|
||||
|
||||
# 获取最大对象信息
|
||||
memory_info["largest_objects"] = self._get_largest_objects(10)
|
||||
try:
|
||||
memory_info["largest_objects"] = self._get_largest_objects(10)
|
||||
except Exception as e:
|
||||
logger.warning(f"获取大对象列表失败: {e}")
|
||||
memory_info["largest_objects"] = []
|
||||
|
||||
return memory_info
|
||||
except Exception as e:
|
||||
|
||||
@@ -70,4 +70,4 @@ cf_clearance~=0.31.0
|
||||
oss2~=2.19.1
|
||||
tqdm~=4.67.1
|
||||
setuptools~=78.1.0
|
||||
pympler~=0.9
|
||||
pympler~=1.1
|
||||
|
||||
Reference in New Issue
Block a user