fix: EasyOCR内存不足时强制CPU模式,避免CUDA加载导致系统冻结
- monitor.py: 内存阈值从2GB提高到3GB,CUDA加载torch需要大量内存 - easyocr_worker.py: 新增物理内存预检(3GB阈值),不足时强制CPU模式 - easyocr_worker.py: _init_reader()再次检查物理内存,双重保障 - 改进错误日志:记录内存详细信息(总量、使用率) - 解决:内存不足时仍加载CUDA导致电脑冻结的问题
This commit is contained in:
+39
-2
@@ -97,8 +97,27 @@ try:
|
||||
os.environ.setdefault("OMP_NUM_THREADS", "1")
|
||||
os.environ.setdefault("MKL_NUM_THREADS", "1")
|
||||
|
||||
# ── 预检:虚拟内存是否足够加载 CUDA 库(cufft64_11.dll ~800MB) ──
|
||||
# ── 预检:物理内存+虚拟内存是否足够加载 CUDA 库 ──
|
||||
_vm = _get_virtual_memory_info()
|
||||
# 检查物理内存:CUDA加载需要足够物理内存,否则会使用页面文件导致冻结
|
||||
try:
|
||||
import psutil
|
||||
_mem = psutil.virtual_memory()
|
||||
_avail_phys_gb = _mem.available / (1024**3)
|
||||
if _avail_phys_gb < 3.0:
|
||||
_msg = (
|
||||
f"物理内存不足: 剩余{_avail_phys_gb:.1f}GB"
|
||||
f"(总计{_mem.total / (1024**3):.1f}GB,使用{_mem.percent}%)"
|
||||
f",CUDA加载需要≥3GB物理内存"
|
||||
)
|
||||
_write_crash_log(f"{datetime.now()} [easyocr_worker] 物理内存预检失败: {_msg}")
|
||||
# 设置环境变量强制CPU模式,而不是直接退出
|
||||
os.environ["EASYOCR_FORCE_CPU"] = "1"
|
||||
sys.stderr.write(f"[easyocr_worker] ⚠️ {_msg},降级CPU模式\n")
|
||||
sys.stderr.flush()
|
||||
except Exception:
|
||||
pass # psutil不可用时不阻断
|
||||
# 检查页面文件:虚拟内存不足时直接退出(无法运行)
|
||||
if _vm and _vm.get("avail_pagefile_gb", 99) < 2.0:
|
||||
_msg = (
|
||||
f"页面文件不足: 剩余{_vm.get('avail_pagefile_gb', '?')}GB"
|
||||
@@ -132,10 +151,28 @@ except Exception as e:
|
||||
|
||||
def _init_reader():
|
||||
"""初始化 EasyOCR reader(GPU 优先,父进程可强制 CPU)。"""
|
||||
# 先检查环境变量是否强制CPU
|
||||
_force_cpu = os.environ.get("EASYOCR_FORCE_CPU") == "1"
|
||||
|
||||
# 再次检查物理内存:加载torch+CUDA需要大量内存,内存不足时强制CPU
|
||||
if not _force_cpu:
|
||||
try:
|
||||
import psutil
|
||||
_mem = psutil.virtual_memory()
|
||||
_avail_phys_gb = _mem.available / (1024**3)
|
||||
if _avail_phys_gb < 3.0:
|
||||
_force_cpu = True
|
||||
sys.stderr.write(
|
||||
f"[easyocr_worker] ⚠️ 物理内存不足(剩余{_avail_phys_gb:.1f}GB),"
|
||||
f"强制CPU模式(避免CUDA加载导致冻结)\n"
|
||||
)
|
||||
sys.stderr.flush()
|
||||
except Exception:
|
||||
pass # psutil不可用时不阻断
|
||||
|
||||
try:
|
||||
import torch
|
||||
# 父进程 EASYOCR_FORCE_CPU=1 → 强制 CPU(显存反复 OOM 时降级,防冻结)
|
||||
_force_cpu = os.environ.get("EASYOCR_FORCE_CPU") == "1"
|
||||
use_gpu = (not _force_cpu) and torch.cuda.is_available()
|
||||
if use_gpu:
|
||||
# CUDA 健康检查:尝试创建一个小张量,避免驱动/显存问题导致后续崩溃
|
||||
|
||||
+7
-5
@@ -1424,19 +1424,21 @@ class MessageMonitor:
|
||||
# ⭐ EASYOCR_WORKER=1: 让 main.py 检测到 worker 模式,跳过 GUI 初始化
|
||||
_worker_env["EASYOCR_WORKER"] = "1"
|
||||
|
||||
# 内存检测:可用内存 < 2GB 时强制CPU模式,防止OOM崩溃
|
||||
# 内存检测:可用内存 < 3GB 时强制CPU模式,防止CUDA加载导致冻结
|
||||
# CUDA加载torch需要大量内存,物理内存不足时强制使用页面文件会导致系统冻结
|
||||
try:
|
||||
mem = psutil.virtual_memory()
|
||||
available_gb = mem.available / (1024**3)
|
||||
if available_gb < 2.0:
|
||||
if available_gb < 3.0:
|
||||
_worker_env["EASYOCR_FORCE_CPU"] = "1"
|
||||
logger.warning(f"[ocr] 可用内存不足({available_gb:.1f}GB),EasyOCR 子进程强制CPU模式")
|
||||
logger.warning(f"[ocr] 可用内存不足({available_gb:.1f}GB/总{mem.total / (1024**3):.1f}GB,"
|
||||
f"使用{mem.percent}%),EasyOCR 子进程强制CPU模式(避免CUDA加载冻结)")
|
||||
elif self._easyocr_cuda_oom_count >= 2:
|
||||
# ⭐ 连续 CUDA OOM/kernel error → 强制 CPU 模式启动(显存不足时防冻结)
|
||||
_worker_env["EASYOCR_FORCE_CPU"] = "1"
|
||||
logger.warning("[ocr] EasyOCR 连续CUDA错误≥2次,本次强制 CPU 模式启动 worker")
|
||||
except Exception:
|
||||
pass # 获取内存失败不阻断
|
||||
except Exception as e:
|
||||
logger.debug(f"[ocr] 获取内存信息失败({e}),不阻断启动")
|
||||
|
||||
self._easyocr_proc = subprocess.Popen(
|
||||
[sys.executable, '-u', worker_path],
|
||||
|
||||
Reference in New Issue
Block a user