BlockingCollections、Tasks 和 OpenCV 的性能随时间下降

Performance degradation over time with BlockingCollections, Tasks, and OpenCV

我正在使用 Xamarin for Android 和 OpenCV C# 绑定库编写一个简单的光学测量应用程序。

为了将图像采集卡与处理分开,我创建了一些阻塞 collections 来传递原始图像,然后在不同线程之间处理图像。我遇到一个问题,在大约 30 秒的时间里,GUI 显示经过处理的精美流畅的视频(15 秒)到断断续续的视频(10 秒),然后崩溃。

下面的代码显示了 collection 的定义。 OnCameraFrame(代码底部)将每个新帧推入 camframes collection。在 OnCreate 中,我 运行 一个名为 CamProcessor 的任务获取帧,做很多事情,并将其填充到外帧中 collection。然后 OnCameraFrame 获取处理过的帧并将其显示给 GUI。为了这个 post 和测试的目的,我已经完全注释掉了我的所有处理,所以这个问题存在只是通过 collections 传递原始数据。

另一个注意事项是我的 collection 似乎 运行 非常快。我在任何时候都不会超过 1 帧,所以这不是溢出问题(我认为)。

谁能指出为什么此策略效果不佳?

BlockingCollection<Mat> camframes = new BlockingCollection<Mat>(10);
BlockingCollection<Mat> outframes = new BlockingCollection<Mat>(10);
public CameraBridgeViewBase mOpenCvCameraView { get; private set; }

    protected override void OnCreate(Bundle savedInstanceState)
    {
        //LayoutStuff

        mOpenCvCameraView = FindViewById<CameraBridgeViewBase>(Resource.Id.squish_cam);

        Task.Run(() => camProcessor());
    }

    public void camProcessor()
    {
        while (!camframes.IsCompleted)
        {
            Mat frame = new Mat();
            try
            {
                frame = camframes.Take();
            }
            catch (InvalidOperationException) { }

            Mat frameT = frame.T();
            Core.Flip(frame.T(), frameT, 1);
            Imgproc.Resize(frameT, frameT, frame.Size());
            outframes.Add(frameT);
         }
     }

    public Mat OnCameraFrame(CameraBridgeViewBase.ICvCameraViewFrame inputFrame)
    {
        mRgba = inputFrame.Rgba();
        Mat frame = new Mat();
        Task.Run(() => camframes.Add(mRgba));
        try
        {
            frame = outframes.Take();
        }
        catch (InvalidOperationException) { }

        return frame;
    }

查看 Android SDK monitor.bat 输出后,我发现这是内存泄漏。原来这对 Java openCV 包装器很常见,并且是 OpenCV 的垫堆比 C# 预期的大得多的结果,所以它没有被垃圾收集。

解决方案是在每次抓取帧时附加这些:

             GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
             GC.Collect();
             GC.WaitForPendingFinalizers();