I believe I am witnessing a memory leak in the following Python code that calls OpenCV functions.
Can you reproduce this? Why does this happen? How can I work around it or fix it?
My environment:
- macOS (10.12 and 10.13)
- Python 3.8.10
- OpenCV 3.4.18
- NumPy 1.24.4
I've now also tested it on another machine in Python 3.9.1 with OpenCV 4.10.0 and NumPy 2.02 and experience the same behavior.
I believe it's linked to cv2.imshow
. With each loop iteration (i.e. every time the image updates) the memory usage of Python increases by an amount relative to the size of the image.
Adding small = cv2.resize(img,(640,360))
and changing the imshow line to cv2.imshow('Image',small)
makes the RAM increase by a much smaller amount.
By inserting a continue
statement above the imshow
call, and thereby skipping imshow
altogether, makes the RAM stay more or less unchanged throughout the loop.
So, I guess this isolates the problem to cv2.imshow
.
import cv2, numpy as np
flag = False
while True:
img = np.zeros((2160,3840,3),np.uint8)
if flag:
img = cv2.circle(img, (1920,1080),128,(255,255,255),-1)
flag = not flag
cv2.imshow('Image',img)
k = cv2.waitKey()
cv2.destroyAllWindows()
if k == 27:
break
I believe I am witnessing a memory leak in the following Python code that calls OpenCV functions.
Can you reproduce this? Why does this happen? How can I work around it or fix it?
My environment:
- macOS (10.12 and 10.13)
- Python 3.8.10
- OpenCV 3.4.18
- NumPy 1.24.4
I've now also tested it on another machine in Python 3.9.1 with OpenCV 4.10.0 and NumPy 2.02 and experience the same behavior.
I believe it's linked to cv2.imshow
. With each loop iteration (i.e. every time the image updates) the memory usage of Python increases by an amount relative to the size of the image.
Adding small = cv2.resize(img,(640,360))
and changing the imshow line to cv2.imshow('Image',small)
makes the RAM increase by a much smaller amount.
By inserting a continue
statement above the imshow
call, and thereby skipping imshow
altogether, makes the RAM stay more or less unchanged throughout the loop.
So, I guess this isolates the problem to cv2.imshow
.
import cv2, numpy as np
flag = False
while True:
img = np.zeros((2160,3840,3),np.uint8)
if flag:
img = cv2.circle(img, (1920,1080),128,(255,255,255),-1)
flag = not flag
cv2.imshow('Image',img)
k = cv2.waitKey()
cv2.destroyAllWindows()
if k == 27:
break
Share
Improve this question
edited 22 hours ago
Christoph Rackwitz
15.5k5 gold badges39 silver badges51 bronze badges
asked 2 days ago
user2268171user2268171
351 silver badge6 bronze badges
7
|
Show 2 more comments
3 Answers
Reset to default 1Is there a reason you are using old version of python CV and NP? I'm on the following versions and have no problems when I copy your snippet here:
OpenCV: 4.10.0
NumPy: 2.1.0
Python: 3.12.5
If you can update you probably should. Is there large functional difference is the major versions that would stop you from updating? If there are, maybe post the relevant code. There should be a way to adjust it to work with the new versions.
I believe it's linked to cv2.imshow. I have not been able to figure out why it's happening and how to fix it, though.
The problem can be fixed.
With Python 3.12.9 and Windows 10
- On line 7 including boolean
if not flag:
- On line 8, decrement the x and y coordinates so you can see the circle.
- On line 9, comment out
#flag = not flag
Snippet:
import cv2, numpy as np
flag = False
while True:
img = np.zeros((2160,3840,3),np.uint8)
if not flag:
img = cv2.circle(img, (640,480),128,(255,255,255),-1)
#flag = not flag
cv2.imshow('Image', img)
k = cv2.waitKey(0)
cv2.destroyAllWindows()
if k == 27:
break
Screenshot:
Thanks to user Christoph Rackwitz, the cause of the problem was identified as cv2.destroyAllWindows()
.
It seems to be present only on Mac systems and a bug report was filed, but apparently, there aren't currently any plans on fixing it.
flag
literally affects nothing that uses memory. I would strongly recommend against rewarding answers that neither repro the problem nor do anything that could even theoretically affect the problem. – Christoph Rackwitz Commented yesterdayprint(cv2.getBuildInformation())
– Christoph Rackwitz Commented 22 hours agodestroyAllWindows
being called in every iteration. is this required to provoke the leak? that's a terrible thing to do in general, unless it's actually intended. – Christoph Rackwitz Commented 22 hours agodestroyAllWindows
got rid of the leak! The other stuff (flag
andcv2.circle
) didn't affect anything. And for the sake of it, this is what was in the GUI section of the build info:Cocoa: YES, VTK support: NO
. Thank you for your help! – user2268171 Commented 21 hours ago