Error with 'A callback was made on a garbage collected delegate'

These days we have been working with OpenCV and figured out a very strange issue.

Process terminated. A callback was made on a garbage collected delegate of type 'OpenCvSharp!OpenCvSharp.MouseCallback::Invoke'.
at OpenCvSharp.NativeMethods.highgui_waitKey(Int32, Int32 ByRef)
at OpenCvSharp.NativeMethods.highgui_waitKey(Int32, Int32 ByRef)
at Daenet.ProductIdentification.Core.ProductRecognizer+<>c__DisplayClass12_0.b__0()

Independent on OpenCV, this seems to be a very unexpected error, which has a root in the way how handlers are natively subscribed in the API, which you use (in my case OpenCV).

Here is the code, which causes the exception.

    using (Mat image = new Mat()) // Frame image buffer
   {
    while (token.IsCancellationRequested == false)
    {
                       
                        capture.Read(image); 
                        if (image.Empty())
                            break;
                        
             var keyPressed = Cv2.WaitKey(delay);   // THIS COUSES THE EXCEPTION
    }
   }

When you run the application in VS (usually Debug mode) all works fine. However, after publishing of the application (no matter how => framework independent, release , single assembly, etc.), the application will fail.

The problem is internally in the registration of the key-handler inside of implementation of the method WaitKey. I guess, there is a subscription of the key-handler as anonymous method. For some reason .NET does not like this.

So, I did following. I moved the declaration of keyPressed to the class scope and declared it a s member variable. I didn't dig in MSIL to see what kind of "de-optimization" happen under the hub, but it "solves" the problem.

    int keyPressed; // THIS WORKS!
    
    using (Mat image = new Mat()) // Frame image buffer
   {
    while (token.IsCancellationRequested == false)
    {
                       
                        capture.Read(image); 
                        if (image.Empty())
                            break;
                        
             keyPressed = Cv2.WaitKey(delay);   
    }
   }

Please not, this is very unusual work-around. To understand wht exactly happen the analysis of MSIL (if even not deeper machine code) might be required.


comments powered by Disqus