perf(debug): 内存监控增强为 100ms 采样 + 多维度指标

- 采样间隔从 1s 降到 100ms,spike 阈值降到 50MB
- 增加 uss/shared/private/data/dirty/compressed 等指标
- 更贴近 macOS 活动监视器'内存'列的统计口径
This commit is contained in:
JOJO 2026-07-17 12:16:16 +08:00
parent faef998a9a
commit 2b131de702

View File

@ -93,11 +93,40 @@ def _current_vms_mb() -> Optional[float]:
return None
def get_memory_info() -> Dict[str, Optional[float]]:
return {
def _get_detailed_memory_info() -> Dict[str, Optional[float]]:
"""获取更详细的内存指标,更接近 macOS 活动监视器。"""
result: Dict[str, Optional[float]] = {
"rss_mb": _current_rss_mb(),
"vms_mb": _current_vms_mb(),
"uss_mb": None,
"shared_mb": None,
"private_mb": None,
"data_mb": None,
"dirty_mb": None,
"compressed_mb": None,
}
try:
import psutil
proc = psutil.Process()
info = proc.memory_info()
# uss 只在 memory_full_info() 中提供
try:
full = proc.memory_full_info()
result["uss_mb"] = getattr(full, "uss", None) / (1024 * 1024) if getattr(full, "uss", None) else None
result["compressed_mb"] = getattr(full, "compressed", None) / (1024 * 1024) if getattr(full, "compressed", None) else None
except Exception:
pass
result["shared_mb"] = getattr(info, "shared", None) / (1024 * 1024) if getattr(info, "shared", None) else None
result["private_mb"] = getattr(info, "private", None) / (1024 * 1024) if getattr(info, "private", None) else None
result["data_mb"] = getattr(info, "data", None) / (1024 * 1024) if getattr(info, "data", None) else None
result["dirty_mb"] = getattr(info, "dirty", None) / (1024 * 1024) if getattr(info, "dirty", None) else None
except Exception:
pass
return result
def get_memory_info() -> Dict[str, Optional[float]]:
return _get_detailed_memory_info()
def _estimate_text_size(text: Any) -> int:
@ -247,20 +276,21 @@ class TopAllocator:
def _periodic_sampling(
interval_seconds: float = 1.0,
spike_threshold_mb: float = 100.0,
max_records: int = 3,
interval_seconds: float = 0.1,
spike_threshold_mb: float = 50.0,
max_records: int = 10,
) -> None:
"""后台线程:每采样一次内存,发现快速增长或峰值时记录。"""
"""后台线程:每 100ms 采样一次内存,发现快速增长或峰值时记录。"""
global _last_sample_rss_mb, _peak_rss_mb
records_since_spike = 0
last_regular_log = 0.0
while ENABLED:
try:
info = get_memory_info()
rss = info.get("rss_mb")
vms = info.get("vms_mb")
if rss is not None:
spike = False
delta = None
if _last_sample_rss_mb is not None:
delta = rss - _last_sample_rss_mb
if delta >= spike_threshold_mb:
@ -271,19 +301,16 @@ def _periodic_sampling(
records_since_spike -= 1
log_memory_event(
"memory_periodic_spike",
rss_mb=rss,
vms_mb=vms,
peak_rss_mb=_peak_rss_mb,
delta_from_last_mb=(delta if spike else None),
**info,
delta_from_last_mb=delta,
)
else:
# 每 5 秒记录一次常规采样,避免日志过多
if int(time.time()) % 5 == 0:
now = time.time()
if now - last_regular_log >= 2.0:
last_regular_log = now
log_memory_event(
"memory_periodic_sample",
rss_mb=rss,
vms_mb=vms,
peak_rss_mb=_peak_rss_mb,
**info,
)
except Exception:
pass
@ -291,8 +318,8 @@ def _periodic_sampling(
def start_periodic_sampling(
interval_seconds: float = 1.0,
spike_threshold_mb: float = 100.0,
interval_seconds: float = 0.1,
spike_threshold_mb: float = 50.0,
) -> None:
"""启动后台内存采样线程。幂等:重复调用不会启动多个线程。"""
global _sample_thread