Skip to content

Commit

Permalink
Fix DmaAllocator memory leak when closing camera
Browse files Browse the repository at this point in the history
When closing the camera, the allocator was not closing the open file
descriptors, causing a memory leak. Fixed by closing the file
descriptors and deleting the allocator when closing the camera.

Signed-off-by: William Vinnicombe <[email protected]>
  • Loading branch information
will-v-pi committed Dec 7, 2023
1 parent 435c76f commit fbaf417
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 1 deletion.
3 changes: 3 additions & 0 deletions picamera2/allocators/allocator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def acquire(self, bufs):
def release(self, bufs):
pass

def close(self):
pass


class Sync:
"""Base class for allocator syncronisations"""
Expand Down
12 changes: 12 additions & 0 deletions picamera2/allocators/dmaallocator.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@ def cleanup(self):
for k in [k for k, v in self.mapped_buffers.items() if v.closed]:
del self.mapped_buffers[k]

def close(self):
self.libcamera_fds = []
self.cleanup()
# Close our copies of fds
for fd in self.open_fds:
os.close(fd)
self.frame_buffers = {}
self.open_fds = []

def __del__(self):
self.close()

class DmaSync(Sync):
"""Dma Buffer Sync"""

Expand Down
5 changes: 4 additions & 1 deletion picamera2/picamera2.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import picamera2.formats as formats
import picamera2.platform as Platform
import picamera2.utils as utils
from picamera2.allocators import DmaAllocator
from picamera2.allocators import Allocator, DmaAllocator
from picamera2.encoders import Encoder, H264Encoder, MJPEGEncoder, Quality
from picamera2.outputs import FfmpegOutput, FileOutput
from picamera2.previews import DrmPreview, NullPreview, QtGlPreview, QtPreview
Expand Down Expand Up @@ -622,6 +622,9 @@ def close(self) -> None:
self.video_configuration_ = None
self.notifymeread.close()
os.close(self.notifyme_w)
# Clean up the allocator
del self.allocator
self.allocator = Allocator()
_log.info('Camera closed successfully.')

@staticmethod
Expand Down
18 changes: 18 additions & 0 deletions tests/allocator_leak_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/python3

# Test that the allocators don't leak

from picamera2 import Picamera2
from picamera2.allocators import DmaAllocator, LibcameraAllocator

for _ in range(200):
picam2 = Picamera2()
picam2.allocator = LibcameraAllocator(picam2.camera)
picam2.configure()
picam2.close()

for _ in range(200):
picam2 = Picamera2()
picam2.allocator = DmaAllocator()
picam2.configure()
picam2.close()
1 change: 1 addition & 0 deletions tests/test_list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ tests/quality_check.py
tests/qt_gl_preview_test.py
tests/stop_slow_framerate.py
tests/allocator_test.py
tests/allocator_leak_test.py

0 comments on commit fbaf417

Please sign in to comment.