diff --git a/src/Uno.UI/UI/Xaml/FrameworkTemplatePool.cs b/src/Uno.UI/UI/Xaml/FrameworkTemplatePool.cs index 3d760f5cd29a..0f91d18db70a 100644 --- a/src/Uno.UI/UI/Xaml/FrameworkTemplatePool.cs +++ b/src/Uno.UI/UI/Xaml/FrameworkTemplatePool.cs @@ -1,4 +1,8 @@ -using System; +#if __WASM__ +#define USE_HARD_REFERENCES +#endif + +using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; @@ -83,6 +87,21 @@ public static class TraceProvider private readonly Stopwatch _watch = new Stopwatch(); private readonly Dictionary> _pooledInstances = new Dictionary>(FrameworkTemplate.FrameworkTemplateEqualityComparer.Default); +#if USE_HARD_REFERENCES + /// + /// List of instances managed by the pool + /// + /// + /// This list is required to avoid the GC to collect the instances. Othewise, the pooled instance + /// may never get its Parent property set to null, and the pool will never get notified that an instance + /// can be reused. + /// + /// The root of the behavior is linked to WeakReferences to objects pending for finalizers are considered + /// null, something that does not happen on Xamarin.iOS/Android. + /// + private readonly HashSet _activeInstances = new HashSet(); +#endif + /// /// Determines the duration for which a pooled template stays alive. /// @@ -160,7 +179,7 @@ internal View DequeueTemplate(FrameworkTemplate template) if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) { - this.Log().Debug($"Creating new template, id={GetTemplateDebugId(template)}"); + this.Log().Debug($"Creating new template, id={GetTemplateDebugId(template)} IsPoolingEnabled:{IsPoolingEnabled}"); } instance = template.LoadContent(); @@ -187,6 +206,9 @@ internal View DequeueTemplate(FrameworkTemplate template) } } +#if USE_HARD_REFERENCES + _activeInstances.Add(instance); +#endif return instance; } @@ -220,7 +242,13 @@ private void OnParentChanged(object instance, object key, DependencyObjectParent PropagateOnTemplateReused(instance); - list.Add(new TemplateEntry(_watch.Elapsed, instance as View)); + var item = instance as View; + + list.Add(new TemplateEntry(_watch.Elapsed, item)); + +#if USE_HARD_REFERENCES + _activeInstances.Remove(item); +#endif if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) {