从相机读取帧时 RAM 使用量增加

RAM usage increasing when reading frames from camera

我正在使用 AForge 库进行一些测试。我正在尝试读取来自我的 USB 相机(帧)的数据。它工作得很好,但唯一的问题是 RAM。它泄漏。似乎一帧需要大约 30 KB,但使用的内存不断增加。

这是我的代码:

Imports AForge
Imports AForge.Controls
Imports AForge.Video
Imports AForge.Video.DirectShow
Imports System.Threading
Imports System.IO
Imports System.Collections.Concurrent
Imports System.ComponentModel

Public Class Form1
    Dim sources As New FilterInfoCollection(FilterCategory.VideoInputDevice)
    Dim WithEvents device As VideoCaptureDevice
    Dim count As Long, bit As Bitmap
    Dim read As New Thread(AddressOf read_que)
    Dim pic_que As New ConcurrentQueue(Of Bitmap)


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each cam As FilterInfo In sources
            ComboBox1.Items.Add(cam.Name)
        Next
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        device = New VideoCaptureDevice(sources(ComboBox1.SelectedIndex).MonikerString)
        AddHandler device.NewFrame, new Video.NewFrameEventHandler(AddressOf frame)

        device.WaitForStop()
        device.Start()
    End Sub

    Sub frame(obj As Object, args As NewFrameEventArgs)
        If bit IsNot Nothing Then
            bit.Dispose()
            bit = Nothing
        End If
        bit = New Bitmap(args.Frame)

        If PictureBox1.Image IsNot Nothing Then
            PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image.Dispose()))
        End If

        PictureBox1.Image =bit ' or ... = Imaging.Image.Clone(args.Frame)

    End Sub
End Class

我什至尝试将所有帧放在一个并发队列中,然后在一个单独的线程中读取它(我发布了似乎占用最少 ram 内存的简化版本)。 但是还有另一个问题(这不是那么重要):当我启动应用程序时,图片框是空白的,使用的 ram 是 16 MB(常量 - 所以它不起作用)。

只有当我进入任务管理器并按下结束进程(实际上没有关闭它)时,它才会开始显示框架。我认为它与 GUI 相关(当我按下 End Process 时,它可能会触发一个启动帧读取的事件 class?)。

只是在随机时间它似乎从第一次开始工作(这确实可能是相机的问题,因为它很旧并且只能在 XP 上工作所以我不得不使用 .NET Framework 4)。

哪里出了问题(主要是内存泄漏)?

试试这个:

Sub frame(obj As Object, args As NewFrameEventArgs)
    If Me.InvokeRequired Then
        Me.BeginInvoke(Sub() frame(obj, args))
    Else
        Dim oldImage = PictureBox1.Image

        Dim bitmap = New Bitmap(args.Frame)
        args.Frame.Dispose() 'Not sure if it has a Dispose
        PictureBox1.Image = bitmap

        If oldImage IsNot Nothing Then oldImage.Dispose()

    End If
End Sub

解决了。感谢您的所有帮助,但我知道我的代码可以正常工作(我在委托之前使用过在图片框上绘制,因此它是线程安全的——我提供的代码是 "quick and dirty")。问题是......虚拟机。我在虚拟机上测试代码。它适用于普通 PC。

代码现在看起来像这样:

Imports AForge
Imports AForge.Controls
Imports AForge.Video
Imports AForge.Video.DirectShow
Imports System.Threading
Imports System.IO
Imports System.Collections.Concurrent
Imports System.ComponentModel

Public Class Form1
    Dim sources As New FilterInfoCollection(FilterCategory.VideoInputDevice)
    Dim device As VideoCaptureDevice
    Delegate Sub lp(ByRef pic As Bitmap)
    Delegate Sub lpp(nr As Integer, nr2 As Integer)
    Delegate Sub slp()
    Dim count As Long, bit As Bitmap
    Dim read As New Thread(AddressOf read_que)
    Dim pic_que As New ConcurrentQueue(Of Bitmap)


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each cam As FilterInfo In sources
            ComboBox1.Items.Add(cam.Name)
        Next
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        device = New VideoCaptureDevice(sources(ComboBox1.SelectedIndex).MonikerString)
        AddHandler device.NewFrame, new Video.NewFrameEventHandler(AddressOf frame)

        'device.WaitForStop()
        device.Start()

        'read.IsBackground = True
        'read.Start()
    End Sub

    Sub frame(obj As Object, args As NewFrameEventArgs)
        'If bit IsNot Nothing Then
        '    bit.Dispose()
        '    bit = Nothing
        'End If
        'bit = New Bitmap(args.Frame)

        If PictureBox1.Image IsNot Nothing Then
            PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image.Dispose()))
        End If

        PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image = Imaging.Image.Clone(args.Frame))) 'Imaging.Image.Clone(args.Frame) ' or ...=bit
    End Sub
End Class