Python摄像头循环采集脚本内存持续增长问题求助
Python摄像头循环采集脚本内存持续增长问题求助
我用树莓派4B搭配13MP USB摄像头写了个Python脚本,功能是采集图片后上传到服务器,下面是简化后的版本(能复现内存增长的问题)。每次循环采集图片后,内存占用都会上涨,最后直接把脚本搞挂了。我已经试过用
del删除变量、把变量设为None,还手动调用了垃圾回收,但都没效果。附上内存占用的截图:
我的代码如下:
import cv2, psutil, os, gc, time def takepic(): frame = None cw, ch = 4000, 3000 cap = cv2.VideoCapture(0) print('click!') cap.set(cv2.CAP_PROP_FRAME_WIDTH, cw) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, ch) time.sleep(0.6) suc, frame = cap.read() cap.release() process = psutil.Process(os.getpid()) print(f'Memory Used {round(process.memory_percent(), 2)}%') resizeit(frame) def resizeit(img): small = cv2.resize(img, (0,0), fx=0.5, fy=0.5) del small del img print(gc.get_count()) gc.collect() print(gc.get_count()) time.sleep(1) takepic() takepic()
兄弟我看了你的代码,一眼就发现了核心问题——递归调用导致的调用栈无限累积!你在resizeit函数最后又调用了takepic(),这相当于开启了无限递归模式:每一次递归都会在Python的调用栈里新增一个栈帧,哪怕你手动del变量、触发GC,这些栈帧本身占用的内存也不会被释放,因为函数从来没有真正返回过,栈帧会一直堆积,内存自然越涨越高。
另外OpenCV的底层操作偶尔会有小的内存泄漏,但你的主要问题肯定是递归结构。下面给你几个针对性的解决思路:
1. 把递归改成循环(最关键的一步)
放弃递归调用,改用while True循环实现重复采集,这样每次函数执行完后栈帧会被正常释放,内存就能被GC回收了。修改后的代码示例:
import cv2, psutil, os, gc, time def takepic(): frame = None cw, ch = 4000, 3000 cap = cv2.VideoCapture(0) try: print('click!') cap.set(cv2.CAP_PROP_FRAME_WIDTH, cw) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, ch) time.sleep(0.6) suc, frame = cap.read() finally: cap.release() # 用try-finally确保摄像头资源必被释放 process = psutil.Process(os.getpid()) print(f'Memory Used {round(process.memory_info().rss / 1024 / 1024, 2)} MB') return frame def resizeit(img): small = cv2.resize(img, (0,0), fx=0.5, fy=0.5) print(gc.get_count()) gc.collect() print(gc.get_count()) time.sleep(1) # 用循环代替递归,避免栈帧堆积 if __name__ == "__main__": while True: frame = takepic() resizeit(frame) del frame # 手动释放帧引用,帮助GC更快回收
2. 优化OpenCV资源处理
- 用
try-finally包裹摄像头操作,避免异常情况下资源没被释放; - 如果还是有内存缓慢增长,可以尝试更新OpenCV到最新稳定版(树莓派上执行
pip install --upgrade opencv-python),某些旧版本在处理大分辨率USB摄像头帧时存在已知的内存泄漏问题。
3. 更精准地监控内存
memory_percent()是相对总内存的百分比,有时候不够直观,改成查看常驻内存(RSS)能更清楚看到实际占用的内存大小:
print(f'Memory Used {round(process.memory_info().rss / 1024 / 1024, 2)} MB')
备注:内容来源于stack exchange,提问作者Vanlon
相关产品推荐
相关产品推荐


