4

I have a large Xamarin iOS app which is suffering from random crashes - which I believe to be due to memory issues. Before trying to fix the issues I am trying to ensure I fully understand how to correctly dispose of everything so I have created a very simple example app with a UINavigationController and 2 screens:

Storyboard Layout

My idea was to use the profiler to check I was correctly clearing everything after use so I:

  1. Ran my app with the profiler
  2. Created a snapshot once everything had loaded. (strangely I have to click 3 times before the object growth is 0)
  3. Clicked the "Shows next screen" button and took Snapshot 4.
  4. Clicked the "Go Back" button and then took Snapshot 5.

My aim was for 5 to cancel out 4 so that I knew everything was being disposed correctly. However instead of the object growth being a negative figure it in fact created another 369 objects:

Xamarin Profiler results

I created a dispose method in by Screen2ViewController which I thought would do the trick:

public partial class Screen2ViewController : UIViewController
    {
        public override void ViewDidDisappear (bool animated)
        {
            base.ViewDidDisappear (animated);

            this.Dispose ();
        }
        public Screen2ViewController (IntPtr handle) : base (handle)
        {
        }

        partial void GoBackButton_TouchUpInside (NSObject sender)
        {
            this.NavigationController.PopViewController(true);
        }

        protected override void Dispose (bool disposing)
        {
            this.ReleaseDesignerOutlets ();
            this.View.Dispose ();
            base.Dispose (disposing);
        }
    }

Have I misunderstood the fact that by opening and then closing a new screen I should expect the net object growth to be 0? If not then what have I done wrong in order to not release everything correctly?

Should I be manually calling this.ReleaseDesignerOutlets() or is this called automatically? I did put a break point on it and it never seemed to be called hence adding it to my Dispose method.

Joseph
  • 2,706
  • 6
  • 42
  • 80

2 Answers2

2

A good introduction to where you leak memory is this SO post.

In general we can say that every view needs to be removed from the super view, disposed and nulled. Every reference needs to be broken, so no cycling reference exists. And, even so its not a best practice, calling GC.Collect() is sometimes really helpful.

Also good reads are:

Community
  • 1
  • 1
tequila slammer
  • 2,821
  • 1
  • 18
  • 25
1

The key will be to determine which objects are kept alive in between snapshots, you should open that one to get an idea of what is going on.

There are a number of lazy caches, and lazy initialization processes that will trigger once and will keep objects around for the lifetime of your app. So the first step is to determine which objects are kept around, and then determine what is keeping them around.

miguel.de.icaza
  • 32,654
  • 6
  • 58
  • 76