Xamarin.forms: [macOS] Navigating back from a complex page is highly inefficient

Created on 9 Jun 2018  路  6Comments  路  Source: xamarin/Xamarin.Forms

Description

Navigating back from a complex page is highly inefficient and takes from several seconds to several minutes. In debug I paused the process several times and checked the stack trace (sample attached below) and I guess that the problem is with the recursion in DisposeModelAndChildrenRenderers method (Xamarin.Forms.Platform.MacOS/Platform.cs) that is called many times for the same child elements.

Steps to Reproduce

  1. Navigate to a page with many nested elements (the tree should be very deep, f.e. 15 levels)
  2. Navigate back
  3. After navigation I have to wait because the application is frozen

Expected Behavior

The page should be disposed quickly. Disposing the same page in UWP, iOS nad Android works well.

Actual Behavior

Disposing the page takes from several seconds to several minutes.

Basic Information

  • Version with issue: 3.0.550146
  • Last known good version:
  • IDE: Visual Studio for Mac
  • Platform Target Frameworks:

    • macOS:

  • Affected Devices: macOS

Stack trace

System.Collections.Generic.List<Xamarin.Forms.BindableObject.BindablePropertyContext>.get_Item(int index) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/collections/generic/list.cs:185
Xamarin.Forms.BindableObject.GetContext(Xamarin.Forms.BindableProperty property) in 
Xamarin.Forms.BindableObject.GetValue(Xamarin.Forms.BindableProperty property) in 
Xamarin.Forms.Platform.MacOS.Platform.GetRenderer(Logotec.AppStudio.Client.Views.Label bindable) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Views.Label view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Layouts.SmartGrid view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Views.DynamicView.Section view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Views.DynamicView.Tab view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Views.DynamicView view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Layouts.WrapLayout view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Views.DynamicView.Section view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Views.DynamicView.Tab view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Layouts.SmartGrid view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Views.DynamicView view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Xamarin.Forms.StackLayout view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Layouts.SmartGrid view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Layouts.SmartGrid view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Layouts.SmartGrid view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Xamarin.Forms.ContentPresenter view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Layouts.SmartGrid view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Views.RootFrame view) in 
Xamarin.Forms.Platform.MacOS.Platform.DisposeModelAndChildrenRenderers(Logotec.AppStudio.Client.Pages.ListPage view) in 
Xamarin.Forms.Platform.MacOS.Platform.HandleChildRemoved(Xamarin.Forms.NavigationPage sender, Xamarin.Forms.ElementEventArgs e) in 
Xamarin.Forms.Element.OnDescendantRemoved(Logotec.AppStudio.Client.Pages.ListPage child) in 
Xamarin.Forms.Element.OnChildRemoved(Logotec.AppStudio.Client.Pages.ListPage child) in 
Xamarin.Forms.VisualElement.OnChildRemoved(Logotec.AppStudio.Client.Pages.ListPage child) in 
Xamarin.Forms.Page.OnInternalRemoved(Logotec.AppStudio.Client.Pages.ListPage view) in 
Xamarin.Forms.Page.InternalChildrenOnCollectionChanged(System.Collections.ObjectModel.ObservableCollection<Xamarin.Forms.Element> sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) in 
System.Collections.ObjectModel.ObservableCollection<Xamarin.Forms.Element>.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:288
System.Collections.ObjectModel.ObservableCollection<Xamarin.Forms.Element>.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedAction action, Logotec.AppStudio.Client.Pages.ListPage item, int index) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:351
System.Collections.ObjectModel.ObservableCollection<Xamarin.Forms.Element>.RemoveItem(int index) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:205
System.Collections.ObjectModel.Collection<Xamarin.Forms.Element>.Remove(Logotec.AppStudio.Client.Pages.ListPage item) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/collections/objectmodel/collection.cs:113
Xamarin.Forms.NavigationPage.Xamarin-Forms-INavigationPageController-RemoveAsyncInner() in 
System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(Xamarin.Forms.NavigationPage stateMachine) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1089
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, Xamarin.Forms.NavigationPage state, bool preserveSyncCtx) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:957
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, Xamarin.Forms.NavigationPage state, bool preserveSyncCtx) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:904
System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1070
System.Threading.Tasks.AwaitTaskContinuation.InvokeAction(System.Action state) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:743
System.Threading.Tasks.AwaitTaskContinuation.RunCallback(System.Threading.ContextCallback callback, System.Action state, System.Threading.Tasks.Task currentTask) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:772
System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.Run(System.Threading.Tasks.Task<bool> task, bool canInlineContinuationTask) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:419
System.Threading.Tasks.Task.FinishContinuations() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:3656
System.Threading.Tasks.Task.FinishStageThree() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2373
System.Threading.Tasks.Task<bool>.TrySetResult(bool result) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:488
System.Runtime.CompilerServices.AsyncTaskMethodBuilder<bool>.SetResult(bool result) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:608
Xamarin.Forms.Platform.MacOS.NavigationPageRenderer.OnPop() in 
System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(Xamarin.Forms.Platform.MacOS.NavigationPageRenderer stateMachine) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1089
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, Xamarin.Forms.Platform.MacOS.NavigationPageRenderer state, bool preserveSyncCtx) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:957
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, Xamarin.Forms.Platform.MacOS.NavigationPageRenderer state, bool preserveSyncCtx) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:904
System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1070
System.Threading.Tasks.AwaitTaskContinuation.InvokeAction(System.Action state) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:743
System.Threading.Tasks.AwaitTaskContinuation.RunCallback(System.Threading.ContextCallback callback, System.Action state, System.Threading.Tasks.Task currentTask) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:772
System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.Run(System.Threading.Tasks.Task<bool> task, bool canInlineContinuationTask) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:419
System.Threading.Tasks.Task.FinishContinuations() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:3656
System.Threading.Tasks.Task.FinishStageThree() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2373
System.Threading.Tasks.Task<bool>.TrySetResult(bool result) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:488
System.Runtime.CompilerServices.AsyncTaskMethodBuilder<bool>.SetResult(bool result) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:608
Xamarin.Forms.Platform.MacOS.NavigationPageRenderer.PopPageAsync() in 
System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(Xamarin.Forms.Platform.MacOS.NavigationPageRenderer stateMachine) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1089
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, Xamarin.Forms.Platform.MacOS.NavigationPageRenderer state, bool preserveSyncCtx) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:957
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, Xamarin.Forms.Platform.MacOS.NavigationPageRenderer state, bool preserveSyncCtx) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:904
System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1070
System.Threading.Tasks.AwaitTaskContinuation.InvokeAction(System.Action state) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:743
System.Threading.Tasks.AwaitTaskContinuation.RunCallback(System.Threading.ContextCallback callback, System.Action state, System.Threading.Tasks.Task currentTask) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:772
System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.Run(System.Threading.Tasks.Task<bool> task, bool canInlineContinuationTask) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:419
System.Threading.Tasks.Task.FinishContinuations() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:3656
System.Threading.Tasks.Task.FinishStageThree() in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2373
System.Threading.Tasks.Task<bool>.TrySetResult(bool result) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:488
System.Threading.Tasks.TaskCompletionSource<bool>.TrySetResult(bool result) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskCompletionSource.cs:298
System.Threading.Tasks.TaskCompletionSource<bool>.SetResult(bool result) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskCompletionSource.cs:321
Xamarin.Forms.Platform.MacOS.NSViewControllerExtensions.<bool>() in 
ObjCRuntime.Trampolines.SDAction.Invoke(System.IntPtr block) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/ObjCRuntime/Trampolines.g.cs:11548
AppKit.NSApplication.NSApplicationMain() in 
AppKit.NSApplication.Main(string[] args) in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.178/src/Xamarin.Mac/AppKit/NSApplication.cs:100
LogotecAppStudio.macOS.MainClass.Main(string[] args) in /Users/kulikow/Projects/AppStudio2018/LogotecAppStudio/LogotecAppStudio.macOS/Main.cs:11
5 low macOS bug

All 6 comments

It comes down to the:
DisposeModelAndChildrenRenderers(child)

call in:

internal static void DisposeModelAndChildrenRenderers(Element view).

If you comment it out you can keep moving forward but my suspicion is you will have memory leaks. I unfortunately dont have any tooling that lets me test what is leaking or not on our code.

I guess the question is, does it need to be recursive?

Please provide a repo so we can make sure we are looking at the same sample.

Thanks

I attached a sample with the problem:

pageDisposing.zip

  1. Open and run in Visual Studio for Mac
  2. Click "Navigate", after a while a new complex page appears and after 5 seconds it navigates back
  3. Try to click "Navigate" again - the interface is frozen until the complex page is disposed, which takes much longer than showing it.

@rmarinho Can you confirm that the sample behaves the same way?

Repro appears to behave as described.

Is it possible to include the fix for this issue in the next release of Xmarin.Forms 3.1 or 3.2 NuGet package?

Sorry @slakul but I think it will only be on 3.3.0-pre1

Was this page helpful?
0 / 5 - 0 ratings