Bug 44047 - Memory leak when using SetBackButtonTitle on iOS
Summary: Memory leak when using SetBackButtonTitle on iOS
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 2.3.2
Hardware: PC Mac OS
: --- normal
Target Milestone: ---
Assignee: Bugzilla
Depends on:
Reported: 2016-09-07 11:11 UTC by Falko Schindler
Modified: 2017-07-12 11:50 UTC (History)
6 users (show)

Tags: ac
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Falko Schindler 2016-09-07 11:11:10 UTC
I discovered a memory leak when using NavigationPage.SetBackButtonTitle. The minimal example I came up with for reproducing the bug is as follows.

There is a master-detail page with a "Menu" (master) and a "Start" page (detail). The start page contains a button pushing a "Special" page. An finally, the special page contains a button pushing another "Empty" content page.

The start page outputs to the console when being constructed or destructed. So basically we expect to see "Constructor" and "Destructor" outputs when navigating the app. But when repeatedly navigating from menu via start and special page all the way to the empty content page and back, no destructor is called (or at least not every time). When removing the NavigationPage.SetBackButtonTitle command, however, the page is destructed as expected. 

The issue only occurs on iOS.

    public class App : Application
        readonly MasterDetailPage masterDetailPage;

        public App()
            masterDetailPage = new MasterDetailPage {
                Master = new ContentPage {
                    Title = "Menu",
                    Content = new Button {
                        Text = "Open start page",
                        Command = new Command(o => {
                            masterDetailPage.IsPresented = false;
                            masterDetailPage.Detail = new NavigationPage(new StartPage());
                Detail = new NavigationPage(new StartPage()),

            MainPage = masterDetailPage;

        public async Task PushAsync(ContentPage page)
            await (masterDetailPage.Detail as NavigationPage).PushAsync(page);

    public class StartPage : ContentPage
        public StartPage()
            Title = "Start page";
            Content = new Button {
                Text = "Open special page",
                Command = new Command(async o => await (Application.Current as App).PushAsync(new SpecialContentPage())),



    public class SpecialContentPage : ContentPage
        public SpecialContentPage()
            Title = "Special page";
            Content = new Button {
                Text = "Open empty sub page",
                Command = new Command(async p => await (Application.Current as App).PushAsync(new ContentPage {
                    Title = "Empty page",
            NavigationPage.SetBackButtonTitle(this, "Special");

Example output:

2016-09-07 13:02:50.009 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:02:54.292 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:02:59.006 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
Thread finished: <Thread Pool> #3
2016-09-07 13:03:03.775 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:03:08.333 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:03:13.148 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:03:18.559 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:03:23.690 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:03:23.691 SetBackButtonTitleBug.iOS[27698:5640929] Destructor
2016-09-07 13:03:31.283 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:03:31.283 SetBackButtonTitleBug.iOS[27698:5640929] Destructor
2016-09-07 13:03:35.501 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
Thread finished: <Thread Pool> #4
2016-09-07 13:03:40.991 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
Thread finished: <Thread Pool> #2
2016-09-07 13:03:45.863 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:03:50.881 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
2016-09-07 13:03:55.819 SetBackButtonTitleBug.iOS[27698:5640916] Constructor
Comment 1 Rui Marinho 2016-10-04 11:40:59 UTC
Still a issue in 2.3.3
Comment 2 adrianknight89 2016-10-20 16:33:55 UTC
This could be further looked at. 

However, finalizers are not guaranteed to run in a balanced way with constructors. Well, (I think?) they are eventually unless the app is terminated abruptly, but they are not balanced all the time while the app is alive.

GC.Collect() marks live objects that should be "dead" and puts them in a separate async finalization thread. It's this second thread that actually invokes finalizers (destructors).

If you want to ensure finalizers are called, then you need to do

GC.Collect(); // reclaims memory from dead objects and marks new objects dead

GC.WaitForPendingFinalizers(); // waits until finalizers are run

GC.Collect(); // reclaims memory from the newly dead objects and marks new objects dead

I have not run your code. You might want to try the above lines of code and see what happens.
Comment 3 adrianknight89 2016-10-20 16:53:18 UTC
That said, if this is only happening on iOS, it should be looked at.
Comment 4 adrianknight89 2016-11-12 05:12:35 UTC
I just ran your repro with GC.Collect(); followed by GC.WaitForPendingFinalizers(); and was able to get a more balanced constructor-destructor pattern. However, it looks like you were right that SetBackButtonTitle creates a memory leak.

See https://github.com/xamarin/Xamarin.Forms/pull/523
Comment 5 Rui Marinho 2017-02-09 16:10:07 UTC
Should be fixed in 2.3.5-pre1
Comment 6 Saurabh Paunikar 2017-07-12 11:50:00 UTC
Have verified the bug with latest forms build version

Bug is seems to be fixed.

Attaching the screencast & logs for more detail.

Screencast : https://www.screencast.com/t/24tE3J38t