C# FORGE和Windows窗体的内存堆积问题

C# FORGE和Windows窗体的内存堆积问题,c#,winforms,image-processing,aforge,autoscroll,C#,Winforms,Image Processing,Aforge,Autoscroll,我在我的c#windows窗体程序中遇到了一个奇怪的内存堆积现象,这种情况在速度较慢的PC上经常发生,当windows窗体失去焦点或在速度较快的PC上被中断时 我编写的程序使用一个forge从我的网络摄像头获取图像,然后在windows窗体的一个forge picturebox控件(CurrImagePic代码)中显示。图像被切换到图片框中,然后以相机的本机帧速率进行处理,因此它对用户显示为视频,而不是静止图像。图片框是1080x1920,但表单中的空间较小,因此我允许用户在图片周围滚动 在速度

我在我的c#windows窗体程序中遇到了一个奇怪的内存堆积现象,这种情况在速度较慢的PC上经常发生,当windows窗体失去焦点或在速度较快的PC上被中断时

我编写的程序使用一个forge从我的网络摄像头获取图像,然后在windows窗体的一个forge picturebox控件(CurrImagePic代码)中显示。图像被切换到图片框中,然后以相机的本机帧速率进行处理,因此它对用户显示为视频,而不是静止图像。图片框是1080x1920,但表单中的空间较小,因此我允许用户在图片周围滚动

在速度较慢的PC上运行约30秒内存稳定后,问题开始出现。在速度更快的电脑上,只有在按住滚动条箭头或在滚动条上单击并拖动时,以及在锁定电脑或打开Ctrl+Alt+Delete菜单时,才会出现问题

问题本身是程序使用的内存开始大量增加,导致内存不足崩溃。这在速度较慢的电脑上是无法阻止的,但在速度较快的电脑上,如果停止滚动或从锁定/Ctrl+alt+delete菜单返回,程序将稳定在较高的内存使用级别。垃圾收集器永远不会收集滚动期间或在锁定菜单中累积的内存。我甚至试着插入一个按钮,按下该按钮时强制执行GC.collect(),但它并没有减少内存使用

我运行了perfmon,发现内存增加是在非托管堆上,但我不知道它是否来自未被处置的位图,或者可能来自什么。这是不可能跟踪,因为它不会发生,除非在上述条件。我尝试过各种解决方案(比如将图像处理移出事件处理程序,甚至使用全局标志和“锁”)语句,以尝试确保一次只有一个线程或帧可以访问图像处理和显示方法,但我没有看到任何更改。事实上,我现在看到一些无法解释的内存使用的小跳跃,这是我在放入锁并将处理移出处理程序之前没有看到的

有人遇到过这样的情况吗?我不知道我需要修复什么,而且我没有从Aforge论坛得到太多帮助。我认为问题是基于我的Aforge事件处理程序和图像处理方法(如果它存在于我的代码中的话)——但我也怀疑这是我所使用的windows窗体代码中更深层次的东西我不是误用了,就是跟不上我代码的要求。代码如下:

//Applicable Globals to this code snippet
private bool ALLOWFRAME = true;
private Object FRAMEKEY = new Object();
private VideoCaptureDevice COMPVID;
private Bitmap TMPLTCAP;
private System.Drawing.Image OLDIMAGE;
private bool RCRDPIC = false;

private void COMPVID_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            //Only process a frame when another is done processing
            if (ALLOWFRAME == true)
            {
                ALLOWFRAME = false;
                Bitmap PassFrame = AForge.Imaging.Image.Clone(eventArgs.Frame);
                ProcessFrame(PassFrame);
                PassFrame.Dispose();
            }
        }

private void ProcessFrame(Bitmap frameIn) 
        {
            lock (FRAMEKEY) 
            { 
                if (OLDIMAGE != null) { OLDIMAGE.Dispose(); }
                //Call comparison method if flag is set.
                if (COMPON == true)
                {
                    Difference TmpltFilter = new Difference(TMPLTCAP);
                    TmpltFilter.ApplyInPlace(frameIn);

                    OLDIMAGE = CurrImagePic.Image;
                    CurrImagePic.Image = AForge.Imaging.Image.Clone(frameIn);
                    OLDIMAGE.Dispose();
                }
                else
                {
                    OLDIMAGE = CurrImagePic.Image;
                    CurrImagePic.Image = AForge.Imaging.Image.Clone(frameIn);
                    OLDIMAGE.Dispose();
                    //Toggle the flag back to false to show it's safe (i.e., comparisons have stopped)
                    //for the result-recording method to copy from the picture box if it is attempting to copy
                    if (RCRDPIC == true)
                    {
                        RCRDPIC = false;
                    }
                }
                ALLOWFRAME = true;
            }
        }

一种经常提高性能的方法是将图像在内存中排队,并使用计时器控件将它们排在图片框中/显示在图片框中。这样,您可以控制适当的处理,并允许
NewFrame
事件更快地返回,而不是在图像处理中被束缚

另外,在
Timer\u Tick
事件中,尝试执行以下操作:

this.Timer.Stop();
Bitmap image = null;
var temp = this.PictureBox.Image;

lock (FRAMEKEY)
{
    if (this.ImageQueue.Any())
    {
        image = this.ImageQueue.Dequeue();
        if (temp != null) { temp.Dispose(); }
    }
}

this.PictureBox.Image = image;
if (temp != null) { temp.Dispose(); }

this.Timer.Start();

COMPON是真的还是假的?是否会因为帧跳过而发生?Aforge会创建一个帧并调用事件,但该特定帧不会显示,因此永远不会被处理?我不记得Aforge是否会在自己之后清除。如果有人在windows窗体中按下“比较图像”按钮,COMPON是真的。到目前为止,我一直在观察它他对COMPON==false有问题,但我确信它的行为与COMPON==true相同。分支中唯一的区别是运行差分过滤器。如果是帧跳过,我对处理方法的全局锁定不会使帧被忽略吗?另外,为什么只有在抓取scrol时才会发生帧跳过l bar?
frameIn
在您锁定之前已经由aforge创建。如果您只是将
frameIn
分配给您的picturebox而不进行克隆,它是否仍然有效?如果是,aforge不会处理位图本身,因此即使您不使用其中一个帧,它们也会生成。@Jens我的印象是
frameIn
,作为方法输入,在方法完成运行时被处理掉。无论如何,我认为这并不能解决问题。如果
frameIn
卡在周围是一个问题,那么不管PC速度或滚动条的拖动,问题不会一直发生吗?另外,
ALLOWFRAME
应该会阻止
ProcessFrame(位图)
如果需要跳过帧(即如果
ProcessFrame(位图)的任何实例),则不会调用
已经存在。我只输入了
以尝试确保执行其他操作的其他线程不会中断。我在这里也在猜测,请不要误解我的意思。将其视为值得检查的内容的指针。您是否也尝试过将其剥离到最小值(如
if(Picturebox1.Image!=null)Picturebox1.Image.Dispose();Picturebox1.Image=frameIn;
等)来缩小问题的范围吗?几年前我确实使用了Aforge网络摄像头功能,但我真的记不清细节了。