Xamarin Performance Advices

Xamarin Best Practices

 

1.    Disposing & unsubscribe

To avoid retain cycles, Xamarin quotes:

In cases where a contained object keeps a link to its container, a few options are available to deal with the cycle:

  • Manually remove the contained object from the container.
  • Call Dispose on the objects.

On UI level, we always try, when we keep a related view variable, to be sure to dispose it at the end of the lifecycle. When we add an event handler “+=”, the second thing to do is to add the “-=”. Notice that it’s easier to unsubscribe a named function rather than a lambda.

Example:

Capture

Of course if the variable is temporary, you can use “using”:

Capture2

Object hierarchies and retain cycles

A quick explanation of retain cycles requires that I quickly summarize how hierarchies of objects are tied together. Specifically: objects in a hierarchy are created, owned and freed in a chain along the hierarchy.

a

In this example, « Some Object » owns Parent which in turn owns the Child.

When the hierarchy is no longer needed, « Some Object » sends a release to the Parent. The Parent’s retainCount hits zero, causing its dealloc method to run. In its dealloc method, it sends a release to the Child, successfully freeing the chain. This is the correct behavior.

The problem of retain cycles occurs when the Child needs a pointer to the Parent for any reason and it chooses to retain the Parent. This alters the diagram to the following:

b

In this diagram, when « Some Object » sends a release to the Parent, the retainCount does not reach zero (since the Child’s retain of the Parent has incremented the retainCount for itself). Since the Parent’s retainCount does not reach zero, its dealloc method never gets called and so it never sends a release to the Child.

This is a retain cycle: with the Parent retaining the Child and the Child retaining the Parent, they continue to exist, cut off from the rest of the objects in the program but keeping themselves alive. They have leaked.

http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html

2.    [Android] Improving Layout Performance

 

The hierarchyviewer tool is our friend, you can see how deep, is your layout, you can check the timings measures:

Capture3.JPG

You should always try to reduce the hierarchy level and avoid layout nesting:

c.png

A simple layout_height value in a huge listview, can cost a lot.

Might seem like a small improvement, but this time is multiplied several times because this layout is used for every item in a list.

An android tool called “lint” help to analyze but it’s not compatible with Xamarin Droid.

Some examples of lint rules are:

  • Use compound drawables – A LinearLayout which contains an ImageView and a TextView can be more efficiently handled as a compound drawable.
  • Merge root frame – If a FrameLayout is the root of a layout and does not provide background or padding etc, it can be replaced with a merge tag which is slightly more efficient.
  • Useless leaf – A layout that has no children or no background can often be removed (since it is invisible) for a flatter and more efficient layout hierarchy.
  • Useless parent – A layout with children that has no siblings, is not a ScrollView or a root layout, and does not have a background, can be removed and have its children moved directly into the parent for a flatter and more efficient layout hierarchy.
  • Deep layouts – Layouts with too much nesting are bad for performance. Consider using flatter layouts such as RelativeLayout or GridLayout to improve performance. The default maximum depth is 10.

 

3.    [ANDROID]Layouts performances controls

 

<include> : it will replace the include tags with the layout, notice that you can override the layout height and width properties.

<merge> : with the merge tag in the reuse layout xml, the include tag will be replace directly by the content of the merge tag, so you will remove one level in the layout hierarchy (the system ignores the <merge> element).

<viewstub> : viewstub is a super light view, you set the layout id and programmatically you will inflate it. So if a large part of the UI is not always required to be always draw and hidden, you can use a viewstub and inflate it on-demand.

 

4.    [ANDROID] ListView & RecyclerView

 

For a simple, non-dynamic, the listview is enough, but in case of dynamic, complex item layout and  huge list, the reclycler is better, the viewholder pattern is use by default, but some features will not be available (mostly the usefull addheader and addfooter functions)

 

5.    [Android] GC

You should learn to read this kind of logs:

  • D/dalvikvm GC_EXPLICIT freed 187K, 4% free 11821K/12224K, paused 0ms+0ms, total 4ms

D/dalvikvm : Virtual machine of the android OS, every GC prints a log

GC_EXPLICIT: An explicit GC, such as when you call gc() (which you should avoid calling and instead trust the GC to run when needed). Check other values:

GC_CONCURRENT : A concurrent GC that frees up memory as your heap begins to fill up.

GC_FOR_MALLOC : A GC caused because your app attempted to allocate memory when your heap was already full, so the system had to stop your app and reclaim memory.

GC_HPROF_DUMP_HEAP : A GC that occurs when you request to create an HPROF file to analyze your heap.

GC_EXTERNAL_ALLOC : This happens only on API level 10 and lower (newer versions allocate everything in the Dalvik heap). A GC for externally allocated memory (such as the pixel data stored in native memory or NIO byte buffers).

Freed 187K: The amount of memory reclaimed from this GC.

4% free 11821K/12224K: Percentage free of the heap and (number of live objects)/(total heap size).

Paused 0ms+0ms, total 4ms: Larger heaps will have larger pause times. Concurrent pause times show two pauses: one at the beginning of the collection and another near the end.

In this example GC_EXPLICIT means that the garbage collector has been explicitly asked to collect, instead of being triggered by high water marks in the heap. Happens all over the place, but most likely when a thread is being killed or when a binder communication is taken down.

  • D/Mono GC_OLD_BRIDGE num-objects 109 num_hash_entries 127 sccs size 127 init 0.00ms df1 0.04ms sort 0.01ms dfs2 0.73ms setup-cb 0.01ms free-data 0.14ms links 19/19/19/1 dfs passes 255/146

The GC Bridge is the mono process to handle the garbage collection for Peer objects (implement IJavaObject, half managed, half native). Old means that we use the classic implementation of this GC.

num-objects: number of bridge objects this pass is considering

num_hash_entries: number of objects processed during this invocation of the bridge code.

In general, the larger the value of num_hash_entries, the more time that the bridge collections will take, and the larger the total time spent collecting will be.

 

  • D/Mono GC_MINOR: (Nursery full) pause 4.67ms, total 4.94ms, bridge 4.69ms promoted 1776K major 2240K los 1375K

The Nursery is where small, new objects are allocated. When the nursery runs out of space, a minor garbage collection will occur. Any live objects will be moved to the major heap.

 

  • D/Mono GC_BRIDGE waiting for bridge processing to finish

?

Pauses up to 150ms for non-interactive applications are tolerable, but pauses above 60ms for very interactive applications (such as games) are a problem.

6.    [ANDROID] Various tips

  • The perfect places to subscribe/unsubscribe to an eventhandler are OnResume/OnPause

 

  • Optimize package size :

d

64-bit runtime support is currently an experimental feature in Xamarin.Android 5.1.x. Remember that 64-bit runtimes are not required in order to run your app on 64-bit devices.

(https://developer.xamarin.com/guides/android/application_fundamentals/cpu_architectures/#Targeting_Multiple_Platforms)

 

  • Launch a crazy monkey on your app:

Open only one android emulator or connect one device, open the adb console prompt from visual studio (e), and type the following line to let the monkey do 500 stupid moves on your app:

 

adb shell monkey -p sport.android.betclic.com -v 500 –pct-appswitch 0

 

http://developer.android.com/tools/help/monkey.html

 

 

7.    [iOS]Various tips

  • Set Views as Opaque When Possible (default value = true) : check view in storyboards and cells too

This will allow the system to draw your views in an optimal manner.

In general avoid transparent layers and blurred borders if possible.

 

  • Watch out for Strong Reference Cycles in iOS

When you add subview which keep a reference to the parent view like this:

 

var container = new Container ();

container.AddSubview (new MyView (container));

 

When the above code creates the Container instance, the C# object will have a strong reference to an Objective-C object. Similarly, the MyView instance will also have a strong reference to an Objective-C object

 

Solutions:

  • Manually break the cycle by setting the link to the container to null.
  • Manually remove the contained object from the container.
  • Call Dispose on the objects.
  • Avoid the cycle by using WeakReference<T> instances to keep a weak reference to the container.
  • Use RemoveFromSuperview (brute force)

 

8.    MvvmCross tips

 

 

 

9.    Webviews

 

  • Implement custom local storage to shared data between native and webview :

RemoveJavascriptInterface / AddJavascriptInterface

  • Watch for the logs and avoid all 404 or 500 web request
  • Android webview debugging : howto
  • iOS webview debugging only possible with simulator:
    • launch your app in the simulator
    • go to the webview page
    • open safari
    • in the menu bar : Develop => Simulator
  • Css & js smaller as possible
  • iOS specific : custom NSUrlProtocol possible (example : ScoreboardLiveRequestInterceptor)

10.                      Various tips

  • Store MonoType in a class property, it’s using reflection and keep a lot of link so heavy memory usage.

11.                      Release Build

  • Remove all console logs or Mvx.Trace
  • Remove dead code, unused variables & classes
  • Disable Android debugging : link

 

 

12.                      Conclusion

 

Ref:

https://cybermaxs.wordpress.com/2015/11/17/performance-tips-tricks-with-xamarin-for-android/

https://developer.xamarin.com/guides/ios/deployment,_testing,_and_metrics/walkthrough_Apples_instrument/

http://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks

https://sites.google.com/site/pyximanew/blog/androidunderstandingddmslogcatmemoryoutputmessages

 

 

Laisser un commentaire