Optimization: minimize GREFs and Java bridging in Xamarin.Android apps

Reducing the number of JNI global references (GREFs) in Xamarin.Android apps can noticeably improve performance of the garbage collector. Each instance of a Managed Callable Wrapper, a Managed Callable Wrapper subclass, or an Android Callable Wrapper will create one GREF. The garbage collection docs call these object types peer objects.

The fewer peer objects, the fewer GREFs, and the more quickly the GC will run. So to a first approximation, apps that do as much as possible in pure C# will have better performance.

Example 1: subclass BaseAdapter instead of ArrayAdapter

One trick that will help reduce unnecessary [Java – C#] bridge interaction is to subclass BaseAdapter rather than ArrayAdapter, and then use pure C# objects (managed objects rather than peer objects) within the adapter. That way, instead of many individual wrappers for each C# object in the array, the GC only has to consider one big wrapper for the whole array.

Links

Advanced Memory Management on iOS and Android

This talk from last year's Evolve carefully explains the problem in slides 31-36. These slides start around 30:30. Note that slide 32 is missing from the video. Slide 32 should be displayed at 32:50. Slide 34 should start at 35:31.

Xamarin API docs for ArrayAdapter

The Remarks section of this API docs page also discusses the issue.

http://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

This blog post discusses several tips for ListView performance, including the BaseAdapter trick briefly near the very end.

Example 2: minimize the number of references to other objects within MCW subclasses

http://docs.xamarin.com/guides/android/advanced_topics/garbage_collection/#Reduce_Referenced_Instances

A similar idea applies to any C# subclass of a Managed Callable Wrapper that has many object references (of any type). Where possible, it's advantageous to aggregate the individual references into a container object, and then reference that single container object instead.

Counter-example: Java arrays containing pure Java objects aren't so bad

As a counter-example, it's OK to have a Java.Util.ArrayList that is initialized with many non-subclassed MCW types. Once the ArrayList is created, the MCW types are no longer needed, so they can be disposed. And as soon as they're disposed, the C# garbage collector will ignore them.

Disposing the MCWs used to initialize the array

http://docs.xamarin.com/guides/android/advanced_topics/garbage_collection/#Disposing_of_Peer_instances

Problematic

public static class MyClass {
    public static void TestGrefs() {
        var arrayList = new Java.Util.ArrayList(500);
        for (var i = 0; i < 500; i++) {
            arrayList.Add(new Android.Graphics.Point(0, i));
        }
    }
}

Better

public static class MyClass {
    public static void TestGrefs() {
        var arrayList = new Java.Util.ArrayList(500);
        for (var i = 0; i < 500; i++) {
            using (var point = new Android.Graphics.Point(0, i)) {
                arrayList.Add(point);
            }
        }
    }
}

Additional considerations

Found a mistake?

Submit a comment or correction

Updates

24 May 2014 Posted