Search code examples
pythonmemoryscreenshotpython-mss

When taking many screenshots with MSS, memory fills quickly and crashes python


Here's my code:

import time
import cv2
import mss
import numpy as np

Frame = [0, 0, 1920, 1080]

def GetFrame():
    monitor = {"top": Frame[0], "left": Frame[1], "width": Frame[2], "height": Frame[3]}
    sct_img = mss.mss().grab(monitor)
    return np.asarray(sct_img)



while (True):
    inimg = GetFrame()
    cv2.imshow("WHY IS MEMORY SO HIGH???????", inimg)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cv2.destroyAllWindows() 

When this runs, it doesn't throw any errors, but looking in task manager, my memory fills quickly (after 200 iterations or so), eventually crashing my desktop, then python. I have looked into garbage collection, with no luck.

Python version 3.7.0
MSS version 4.0.1

Solution

  • Solved the problem myself. The issue was that mss.mss() instances must be closed, they do not automatically close during garbage collection (for whatever reason). The most convenient way to do that is by using a context manager:

    def GetFrame():
        with mss.mss() as sct:
            monitor = {"top": Frame[0], "left": Frame[1], "width": Frame[2], "height": Frame[3]}
            sct_img = sct.grab(monitor)
            return np.asarray(sct_img)
    

    As Tiger-222 points out, we can optimize this further by only creating a single mss.mss() object and using it throughout the entire program:

    monitor = {"top": 0, "left": 0, "width": 1920, "height": 1080}
    
    def get_frame(sct):
        return np.asarray(sct.grab(monitor))
    
    with mss.mss() as sct:
      while True:
        img = get_frame(sct)
        cv2.imshow(img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
          break
    
    cv2.destroyAllWindows()