ImageGrab.grab()运行2小时后抛出OSError: screen grab failed问题求助
解决ImageGrab.grab()长时间运行后抛出OSError的问题
问题成因
- GDI资源泄漏:你的代码调用
im.load()返回像素数组后,原Image对象im未被主动释放。Pillow的ImageGrab在Windows平台依赖系统GDI资源(如设备上下文、位图对象),每次截图创建的这类资源若未及时回收,长时间循环后会耗尽进程可用的GDI资源上限(Windows默认每个进程最多允许10000个GDI对象),最终触发screen grab failed错误。 - 垃圾回收不及时:Python自动垃圾回收可能无法及时清理
Image对象关联的系统资源,高频循环场景下,资源累积速度会超过回收速度。
解决方法
1. 主动释放Image对象资源
修改shot函数,获取像素数据后显式删除Image对象,强制触发资源回收:
from PIL import ImageGrab from threading import Thread import time DELAY = 1.0 def shot(bbox): im = ImageGrab.grab(bbox) pixel_data = im.load() # 显式删除Image对象,释放关联的GDI资源 del im return pixel_data def screen_scan(): while True: shot(None) time.sleep(DELAY) if __name__ == '__main__': Thread(target=screen_scan, daemon=True).start() while True: input()
也可用try-finally确保资源不会因异常泄漏:
def shot(bbox): im = None try: im = ImageGrab.grab(bbox) return im.load() finally: if im is not None: del im
2. 增加异常处理与强制垃圾回收
在循环中捕获OSError,遇到错误时触发强制垃圾回收并短暂重试,避免程序直接崩溃:
import gc def screen_scan(): while True: try: shot(None) except OSError as e: print(f"截图失败: {e},重试中...") gc.collect() # 强制触发垃圾回收,清理未释放的资源 time.sleep(2) # 延长休眠时间,给系统资源释放留缓冲 time.sleep(DELAY)
3. 更换更高效的截图库
如果上述方法仍无法彻底解决问题,可改用mss库——它专门针对屏幕截图优化,资源管理更高效,适合长时间运行场景。
首先安装库:
pip install mss
替换后的示例代码:
from mss import mss from threading import Thread import time DELAY = 1.0 def shot(): with mss() as sct: # 截取主显示器(monitors[1]对应主屏幕,monitors[0]是所有屏幕的组合) sct_img = sct.grab(sct.monitors[1]) # 返回像素数据,用法和Image.load()类似 return sct_img.pixels def screen_scan(): while True: shot() time.sleep(DELAY) if __name__ == '__main__': Thread(target=screen_scan, daemon=True).start() while True: input()
内容的提问来源于stack exchange,提问作者Gygabrain
相关产品推荐
相关产品推荐

