Search code examples
pythonwindows-7memory-leaksgarbage-collectionscreenshot

Memory leak / Python windows 7 screenshots


I have tried the following Python code on a dual monitor system (Windows7) to repeatedly save screenshots. It generates 33 shots of 14.6MB (total 482MB) and then crash. Checking with Process Explorer I can see the amount of used memory raise to about 500MB.

My question is how to stop the memory leak?

import win32gui, win32ui, win32con, win32api
import time
import os


def my_capture(file_name):
    hwin = win32gui.GetDesktopWindow()
    width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
    height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
    left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
    top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
    hwindc = win32gui.GetWindowDC(hwin)
    srcdc = win32ui.CreateDCFromHandle(hwindc)
    memdc = srcdc.CreateCompatibleDC()
    bmp = win32ui.CreateBitmap()    
    bmp.CreateCompatibleBitmap(srcdc, width, height)
    memdc.SelectObject(bmp)
    memdc.BitBlt((0, 0), (width, height), srcdc, (left, top), win32con.SRCCOPY)
    bmp.SaveBitmapFile(memdc, file_name) # 'screenshot.bmp'


def captureAndSave(i):
    if i < 10:
        tmpStr = "00000" + str(i)
    elif i < 100:
        tmpStr = "0000" + str(i)
    elif i < 1000:
        tmpStr = "000" + str(i)
    elif i < 10000:
        tmpStr = "00" + str(i)
    elif i < 100000:
        tmpStr = "0" + str(i)
    else:
        tmpStr = str(i)

    my_capture(tmpStr + '.bmp')


def myMainLoop():
    i = 0
    while 1:
        i = i + 1
        captureAndSave(i)
        time.sleep(0.2)

#-----------------------------------------------------------------------------

if __name__ == '__main__':
    try:
        myMainLoop()        # capure all monitor windows
    except KeyboardInterrupt:
        pass 

I got the base code from: Python windows 7 screenshot without PIL:


Solution

  • You'll want to clean up your bitmaps and DCs, adding something like this after the bitmap is saved;

    win32gui.DeleteObject(bmp.GetHandle())
    memdc.DeleteDC()
    srcdc.DeleteDC()
    win32gui.ReleaseDC(hwin, hwindc)