0

I'm working on a Python application right now that uses PyQt5 and CFFI bindings to libgphoto2.

I have this section of code that will poll the camera every 1/60 of a second to get a preview image and then schedule to draw it on the screen.

def showPreview(self):
    # Do we have a camera loaded at the moment?
    if self.camera:
        try:
            # get data from the camera & turn it into a pixmap
            self.__buffer = self.camera.getPreview().scaled(self.size(), Qt.KeepAspectRatio) # Scale it

            # Schedule a redraw
            self.update()

            # Setup another show preview in 1/60 of a second
            QTimer.singleShot(1000 // 60, self.showPreview)
        except GPhoto2Error as e:
            # Ignore any errors from libgphoto2
            pass

The getPreview() method returns a QImage type.

When I was running this with a camera connected to my application, I noticed that my system's memory usage kept on going up and up. Right I've had it run for about 10 minutes. It started at 0.5% usage and now is up to near 20%.

Correct me if I'm wrong, but shouldn't Python's GC be kicking in and getting rid of the old QImage objects. I suspect that they are lingering on longer than they should be.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Benjamin
  • 1,223
  • 1
  • 13
  • 22
  • Do the memory leaks still occur (albeit more slowly) if you reduce the frame rate to, say, 10 per second? – Jeremy Friesner Jul 01 '17 at 02:57
  • That's not the responsibility of Python's GC necessarily. There are well known memory leaks in QImage for PySide, and it could very well be the bindings (see line 150, this patch is actually not complete, it just minimizes the issue): https://pypkg.com/pypi/matplotlib/src/lib/matplotlib/backends/backend_qt5agg.py – Alex Huszagh Jul 01 '17 at 03:00
  • Yeah it still is, albeit very slowly. – Benjamin Jul 01 '17 at 03:00
  • @Benjamin, you can also force Python to force GC collection, which can help determine if it's a PyQt issue or a Python-level issue. `import gc; gc;collect()` – Alex Huszagh Jul 01 '17 at 03:01
  • @AlexanderHuszagh I was wondering about that too. I'm thinking about avoiding the use of QImage as much as possible (and use some other image manipulation library), but part of the problem is that IIRC, I need QImage for QPainter to draw images. – Benjamin Jul 01 '17 at 03:02
  • 1
    @AlexanderHuszagh as for the `gc.collect()`, I actually did try that before. Same results. – Benjamin Jul 01 '17 at 03:02
  • It might also be memory fragmentation. Sometimes, especially with pooled memory like Python, memory isn't returned to the system all at once, and it can actually be pretty inefficient in returning it. This effectively acts like a memory leak, even though no memory is lost :/ – Alex Huszagh Jul 01 '17 at 03:07
  • Is there anything that I can do here? I don't want my application to use system resources like this. – Benjamin Jul 01 '17 at 03:49
  • 2
    @Benjamin. What **exactly** have you done to identify the source of the leak? How do you know that PyQt / QImage is causing the problem, rather than, say, the CFFI bindings, or your own code? With so many potentially confounding variables in play here, it's impossible to attempt a constructive diagnosis. You need to create a proper test case that reliably reproduces the problem so that others can try it for themselves. – ekhumoro Jul 01 '17 at 13:38

1 Answers1

0

In case it helps, I had a similar memory leak on an application using QImage and QPixmap. Memory was increasing at a rate of 2% every time I uploaded an image. By using QPixmap.scaled (...., Qt.FastTransformation) I achieved a 0.2% increase on every image. The problem is still there, but 10 times smaller. Nothing else was changed in my code. So it must be related to the destructor of QImage/QPixmap.