读取SML串口数据写入PostgreSQL时出现MemoryError求助
问题描述
- 环境:Raspberry Pi 搭配USB红外抄表头读取电表SML格式数据;Python程序运行于Docker容器,校验CRC后写入远程PostgreSQL
- 故障:容器运行约2天后触发未处理异常:
Unhandled exception in thread started by <bound method Thread._bootstrap of <Timer(Thread-40265317, initial 189230468)>> Traceback (most recent call last): File "/usr/local/lib/python3.7/threading.py", line 890, in _bootstrap self._bootstrap_inner() File "/usr/local/lib/python3.7/threading.py", line 914, in _bootstrap_inner self._set_tstate_lock() File "/usr/local/lib/python3.7/threading.py", line 909, in _set_tstate_lock _shutdown_locks.add(self._tstate_lock) MemoryError
- 已排查:嵌套循环、变量重置操作,怀疑日志导致内存溢出但未解决
排查与解决步骤
1. 定位Timer线程泄漏
错误来自Timer线程,Python的threading.Timer若未正确清理,会导致线程锁堆积耗尽内存:
- 检查程序中创建
Timer的逻辑:是否循环创建Timer但未对旧实例调用cancel()?是否Timer回调中递归创建新Timer,导致线程数量持续增长? - 在容器内执行
pstree或ps aux | grep python,观察线程数是否随时间递增。
2. 优化日志输出
若未配置日志轮转,日志堆积会占用容器内存:
- 检查Python日志配置:避免开启DEBUG级别后输出大段原始SML数据;配置日志轮转(如使用
logging.handlers.RotatingFileHandler限制单文件大小)。 - 在
docker-compose.yml中添加Docker日志轮转策略:services: your-service-name: logging: driver: "json-file" options: max-size: "10m" max-file: "3"
3. 修复数据库连接泄漏
若频繁创建数据库连接未关闭,会导致内存占用持续增长:
- 检查
db.py:是否每次写入都新建连接,用完后未调用close()? - 使用连接池(如
psycopg2.pool.SimpleConnectionPool)复用连接,减少重复创建连接的内存消耗。
4. 升级Python版本
Python 3.7的threading模块存在线程锁回收的已知问题,升级到3.8+可修复部分此类问题:
- 修改
Dockerfile基础镜像,例如:FROM python:3.9-slim
5. 内存监控与泄漏定位
添加内存监控代码,定位内存增长来源:
- 用
psutil定期打印内存使用:import psutil import os def log_memory(): proc = psutil.Process(os.getpid()) print(f"当前内存占用: {proc.memory_info().rss / 1024 / 1024:.2f} MB") - 用
tracemalloc跟踪内存分配:import tracemalloc tracemalloc.start() # 插入到程序启动处 # ...运行一段时间后... snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') print("[TOP 10 内存占用点]") for stat in top_stats[:10]: print(stat)
6. 设置Docker资源限制
为容器配置内存上限,避免占用过多树莓派内存,同时便于OOM问题排查:
services: your-service-name: deploy: resources: limits: memory: "256M" reservations: memory: "128M"
内容的提问来源于stack exchange,提问作者thomasme
相关产品推荐
相关产品推荐

