Android Vision Text scanning leaks memory in Xamarin.Android

369 Views Asked by At

After noticing a few crashes on older devices when using TextRecognizer from the library Android.Gms.Vision I decided to profile it using Android Studio and the result was the following:

enter image description here

While the process is running, even if the method ReceiveDetections is empty (no code logic on my side other than instantiating the builder), the memory usage grows really fast, and the app subsequently crashes within one minute. From the profiler I could see that the memory is used in a byte[] variable in the native code.

The interesting fact is that I'm also using the BarcodeDetector from that library, but that's not causing any memory leak. Finally, I also profiled my Xamarin.Android application using the Xamarin profiler, and the Mono code is taking at most a couple of MB, so my code doesn't seem to cause the problem.

I add the code I'm using below:

public class Scanning : Activity, ISurfaceHolderCallback, IProcessor
{
    private SurfaceView surfaceView;
    private CameraSource cameraSource;
    private const int RequestCameraPermissionID = 1001;

    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
    {
        switch (requestCode)
        {
            case RequestCameraPermissionID:
                if (grantResults[0] == Permission.Granted)
                    cameraSource.Start(surfaceView.Holder);
                break;
        }
    }

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        SetContentView(Resource.Layout.Scanning);
        RequestedOrientation = ScreenOrientation.Portrait;

        surfaceView = FindViewById<SurfaceView>(Resource.Id.surfaceView);

        TextRecognizer textRecognizer = new TextRecognizer.Builder(ApplicationContext).Build();

        if (textRecognizer.IsOperational)
        {
            cameraSource = new CameraSource.Builder(ApplicationContext, textRecognizer).Build();

            surfaceView.Holder.AddCallback(this);
            textRecognizer.SetProcessor(this);
        }
    }

    public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height) { }

    public void SurfaceCreated(ISurfaceHolder holder)
    {
        if (CheckSelfPermission(Manifest.Permission.Camera) != Android.Content.PM.Permission.Granted)
        {
            RequestPermissions(new string[]
            {
                Android.Manifest.Permission.Camera
            }, RequestCameraPermissionID);
            return;
        }

        cameraSource.Start(surfaceView.Holder);
    }

    public void SurfaceDestroyed(ISurfaceHolder holder)
    {
        cameraSource.Stop();
    }

    public void ReceiveDetections(Detections detections) { }

    public void Release() { }
}

Am I missing anything on my side, or is it an actual bug of the library?

If yes is there a workaround?

1

There are 1 best solutions below

1
moljac On

MCWs Managed Callable Wrappers (C# code wrapping Android API) might hold reference to some java objects containing other data (Image scanned, text...), so that GC cannot release that memory.

I had similar case in one custom bindings for image recognition.

The solution is to understand which objects might hold references and after they are not needed anymore to manually call GC.Collect().

From this high level view (glance) I would call it in Release() and/or after cameraSource.Stop();

Let me know if that works. Otherwise I'll need repro sample to test it.