Forum Xamarin.Forms

Announcement:

The Xamarin Forums have officially moved to the new Microsoft Q&A experience. Microsoft Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

To create new threads and ask questions head over to Microsoft Q&A for .NET and get involved today.

Xamarin Forms app's Performance degrades after half an hour ???

I have crated an app in Xamarin Forms, now the app will work smoothly for half an hour but when the time passed the application's performance will goes down. I checked with the Xamarin Profiler it shows 400 -500 mb usage with in the half an hour, so what is the solution for this ???? I want to use the application for 7 - 8 hrs. and with this kind of performance we just can't use the application.

Answers

  • ComConComCon DEMember ✭✭

    Make snapshots for every view and compare them.

  • ThekidThekid INMember ✭✭

    you have some sort of memory leak , without any code no one can help you , have you used the emulator? try to identify which part of your code is using so much amount of ram

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    @thekid is right... You're consuming memory. Highly unlikely this is a Xamarin issue. Rather its just bad code design. You're making objects and not disposing of them. Where and how is anyone's guess without code. Are you just adding to collections forever? Do you have globally scoped collections that never empty? How does your app make things? Photos... REST services... whatever it is you're doing your objects are not going out of scope and thus not being disposed of.

  • veeru3112veeru3112 INMember ✭✭

    @Thekid said:
    you have some sort of memory leak , without any code no one can help you , have you used the emulator? try to identify which part of your code is using so much amount of ram

    I just Cleared all the Collection, Static objects, List and also setting BindingContext = null at OnDisappearing but doesn't get any improvement, is this the limitation of Xamarin Forms, we couldn't get the Application Performance like the Native one or else is there any other way then suggest me...

  • LentoManLentoMan SEMember ✭✭

    You can also try setting Content to null in the OnDisappearing, avoid saving any references to pages to try and reuse them (possibly use WeakReferences).

    Use a profiler to find leaks, a good start is to watch the XamarinShow about the Xamarin Profiler. You don't necessarily have to use the Xamarin Profiler to find major memory issues, if your forms app runs in UWP, you can use the Diagnostic Tools to take memory snapshots.

    Write a small loop that displays one page and leaves it again a certain number of times, that way you more easily find reference counts in your snapshots. Perhaps add a delay in between each display attempt to give the page time to render, also try adding a GC.Collect() on each loop.

  • NMackayNMackay GBInsider, University admin
    edited December 2016

    Also remember to clear any attached behaviors in controls when popping the page or it will be retained in memory.

  • veeru3112veeru3112 INMember ✭✭

    @LentoMan said:
    You can also try setting Content to null in the OnDisappearing, avoid saving any references to pages to try and reuse them (possibly use WeakReferences).

    Use a profiler to find leaks, a good start is to watch the XamarinShow about the Xamarin Profiler. You don't necessarily have to use the Xamarin Profiler to find major memory issues, if your forms app runs in UWP, you can use the Diagnostic Tools to take memory snapshots.

    Write a small loop that displays one page and leaves it again a certain number of times, that way you more easily find reference counts in your snapshots. Perhaps add a delay in between each display attempt to give the page time to render, also try adding a GC.Collect() on each loop.

    @LentoMan i tried following approaches,
    1. clear all the static objects/list/collections at onDisappearing
    2. Created ViewModel object singleton
    3. I also implemented lazy loading.
    4. After navigation Pop out the Page from the Navigation Stack
    5. used GC.Collect()- but is wasn't worked
    6. I also checked with the Xamarin Profiler, but it shows me that my app's memory is contentiously increasing by the time i am using application, which probably means that all the above approaches are not able to clear the data.

    So, is this the limitation with the Xamarin Forms or else we have to something else ????

  • ChaseFlorellChaseFlorell CAInsider, University mod

    @NMackay said:
    Also remember to clear any attached behaviours in controls when popping the page or it will be retained in memory.

    I haven't dug into this, but doesn't Forms clean up that kind of stuff on it's own? It would make sense (especially in Xaml) that the framework cleans up after it's self. It would be weird to dispose of Behaviours/Triggers in code that are constructed in xaml.

  • NMackayNMackay GBInsider, University admin
    edited December 2016

    @ChaseFlorell said:

    @NMackay said:
    Also remember to clear any attached behaviours in controls when popping the page or it will be retained in memory.

    I haven't dug into this, but doesn't Forms clean up that kind of stuff on it's own? It would make sense (especially in Xaml) that the framework cleans up after it's self. It would be weird to dispose of Behaviours/Triggers in code that are constructed in xaml.

    It should but no, it doesn't sadly. It totally sucks and is a bugbear of mine with Forms.

    https://developer.xamarin.com/guides/xamarin-forms/behaviors/creating/

    I made them make it more clear in the documentation that you have to clear them but honestly, how many people read all the documentation once they've found out how to make it work?

    I did suggest on the new forum to add the ability to allow automatic behavior cleanup but my suggestion wasn't correctly formatted and I haven't got round to adding posting it again. I did raise the issue internally several times and I'm waiting on a response before suggesting it again.

    My suggestion is to automatically opt in to behavior clean and add a XamlC flag to disable this cleanup it there's a performance hit. As it stands you must clean up your behaviors.

    My pages are littered with this kind of code.

            public void Destroy()
            {
                SearchBarCustomerName.Behaviors.Clear();
                ListviewCustomer.Behaviors.Clear();
            }
    
  • veeru3112veeru3112 INMember ✭✭

    @ClintStLaurent said:
    @thekid is right... You're consuming memory. Highly unlikely this is a Xamarin issue. Rather its just bad code design. You're making objects and not disposing of them. Where and how is anyone's guess without code. Are you just adding to collections forever? Do you have globally scoped collections that never empty? How does your app make things? Photos... REST services... whatever it is you're doing your objects are not going out of scope and thus not being disposed of.

    I am putting list/collection null at onDisappearing of the Xaml page, disposing HTTP client, clearing navigation stack when the page is navigated, but the xamarin profiler will continuously increasing memory.

  • huangjinshehuangjinshe USMember ✭✭✭

    Could you please say first: which platform has that memory leak?

  • ChaseFlorellChaseFlorell CAInsider, University mod

    @nmackay, now I haven't tested this as I'm on holidays, but the source has this.

            ~VisualElement()
            {
                if (!GetIsDefault(BehaviorsProperty)) {
                    var behaviors = GetValue(BehaviorsProperty) as AttachedCollection<Behavior>;
                    behaviors.DetachFrom(this);
                }
    
                if (!GetIsDefault(TriggersProperty)) {
                    var triggers = GetValue(TriggersProperty) as AttachedCollection<Trigger>;
                    triggers.DetachFrom(this);
                }
            }
    

    This triggers the detach bits where the event unsubscription lives.

  • ChaseFlorellChaseFlorell CAInsider, University mod

    Ok, I'm seeing exactly what's going on here now. The damn finalizer doesn't actually get called.

    @NMackay would you say that you call your Destroy() method primarily when the page is popped from the navigation stack?

  • NamyslawSzymaniukNamyslawSzymaniuk USMember ✭✭✭✭
    > @ChaseFlorell said:
    > Ok, I'm seeing exactly what's going on here now. The damn finalizer doesn't actually get called.
    >
    > @NMackay would you say that you call your Destroy() method primarily when the page is popped from the navigation stack?

    I'm adding Behaviors on page OnAppearing and removing on page OnDissapearing, but only because of this thread, didn't faced any issue, till now.
  • ChaseFlorellChaseFlorell CAInsider, University mod
    edited January 2017

    I'm trying something a little differently.

    In the constructor of each page that contains Behaviors, I'm adding the following

    public MyPage()
    {
        InitializeComponent();
    
        // this is what actually matters
        App.OnPagePopped(this, () => {
            SomeControl.Behaviors.Clear();
            OtherControl.Behaviors.Clear();
        });
    }
    

    Then I have a static method on my App class (not actually, but this is how I'm explaining it.. I actually have a custom Navigation Router)

    private Page _currentPage;
    
    public App(){
        var mainPage = new NavigationPage(new MyPage());
        mainPage.Popped += OnPopped;
        mainPage.PoppedToRoot += OnPoppedToRoot;
        _currentPage = mainPage;
        MainPage = mainPage;
    }
    
    public static void OnPagePopped(object sender, Action action) {
        MessagingCenter.Subscribe<Page>(sender, "OnPopped") {
            page => {
                if (page.GetType() != sender.GetType()) return;
    
                action.Invoke();
                MessagingCenter.Unsubscribe<Page>(page, "OnPopped");
            }
        }
    }
    
    private void OnPopped(object sender, EventArgs args){
        MessagingCenter.Send(NavigationStack.LastOrDefault(), "OnPopped");
        _currentPage = NavigationStack.LastOrDefault();
    }
    
    private void PoppedToRoot(object sender, EventArgs args) {
        foreach (var page in NavigationStack)
        {
            MessagingCenter.Send(page, "OnPopped");
        }
        _currentPage = NavigationStack.LastOrDefault();
    }
    
  • NMackayNMackay GBInsider, University admin
    edited January 2017

    @ChaseFlorell

    Thanks for looking into this, I've been away for a few weeks.

    I'm pretty certain the behaviors don't get cleaned. For my MVVM Light apps I used this workaround using navigation pages.

    using Xamarin.Forms;
    using XamFormsTestApp.Data.Services.Common;
    
    namespace XamFormsTestApp.CustomPages
    {
        public class CustomNavigationPage : NavigationPage
        {
    
            public CustomNavigationPage(Page content)
                : base(content)
            {
                Init();
            }
    
            private void Init()
            {
                //this.Pushed += (object sender, NavigationEventArgs e) =>
                //{
                //    //Handle pushing a new screen. 
    
                //};
    
                Popped += (sender, e) =>
                {
                    var navpage = e.Page as IPageLifetime;
                    if (navpage != null)
                    {
                        // Unregister vm of page, message listener etc
                        navpage.CleanupPage();
                    }
                    e.Page.BindingContext = null;
                };
            }
        }
    }
    

    At the moment I'm using Prism and IDestructible (Destroy). It will Clear the page behaviors but there's no nice way to clear control behaviors, IMO the Forms framework should really be doing this.

    https://github.com/PrismLibrary/Prism/blob/master/Source/Xamarin/Prism.Forms/Common/PageUtilities.cs

    There is known issue that it would get called on open pages when you reset the main navigation stack
    https://github.com/PrismLibrary/Prism/issues/862

  • BrianLagunasBrianLagunas USInsider ✭✭✭✭

    @NMackay You can implement IDestructible on the Views and clear the control specific behaviors.

  • NMackayNMackay GBInsider, University admin

    @BrianLagunas

    Hi Brian, that's what I'm doing at present but it would be nice if it could be done automatically by the Forms framework, especially if your new to Forms and not using a nice framework like Prism which makes cleanup mach easier to implement. A lot of people aren't aware of this Forms quirk/feature.

    Happy new year btw, exciting year for Forms and Prism I reckon :smile:

  • BrianLagunasBrianLagunas USInsider ✭✭✭✭

    @NMackay Yeah, this is a real pain in Forms. I was thinking of traversing the XAML element tree and looking for behaviors and removing them automatically, but it was apparent that it would be come an expensive operation. Let's hope that Xamarin comes up with a good solution to this soon.

    Happy New Year to you! I am done with my vacation and will be working on more Prism improvements soon :)

  • ChaseFlorellChaseFlorell CAInsider, University mod

    @NMackay there is a lifecycle proposal in the works, and I've added my two cents around this topic. Feel free to take a read and comment if you have anything further to add.

    discussion/84510/improved-life-cycle-support

  • NMackayNMackay GBInsider, University admin

    @ChaseFlorell

    Thanks, I'm very much keeping an eye on it and a few other threads :smile:

    It would be nice if Forms could take care of UI element resource cleanup automatically, a best guess auto clean-up so to speak which you could override (via a XamlC flag or something).

  • ChaseFlorellChaseFlorell CAInsider, University mod

    I think auto cleanup would need to be smarter than iterating over all the VisualElements and clearing their behaviors. Possibly instead, they'd have to hold a private collection of elements that get behaviors added, and then loop the collection to clear them... dunno though... would that require x:Name to be added? Also, when should the cleanup happen?

  • NMackayNMackay GBInsider, University admin

    It should happen when the page is popped or the navigation stack I'd imagine.

  • ChaseFlorellChaseFlorell CAInsider, University mod

    @NMackay said:
    It should happen when the page is popped or the navigation stack I'd imagine.

    While I totally agree that this is when it should happen, there can be an issue whereby the user wants to cache the page.

    public partial class ConvolutedPage 
    {
        public async void NeverDoThis() {
            var hugeDetailPage  = new HugeDetailPage();
            await Navigation.PushAsync(hugeDetailPage);
    
            await Task.Delay(10000);
            await Navigation.PopAsync();
    
            await Task.Delay(10000);
            await Navigation.PushAsync(hugeDetailPage);
        }
    }
    

    Obviously you'd never do this, but you can see whereby if the user wishes to cache a huge page, the act of Popping it should NOT auto cleanup the Behaviors.

    This is a case in favour of the framework calling an OnRemoved method during the Pop, and allowing us to override it to do our own cleanup.

  • BrianLagunasBrianLagunas USInsider ✭✭✭✭

    @ChaseFlorell Actually, that doesn't do what you think it does. There is no real benefit to caching the XAML pages. Creating the XAML pages is relatively cheap. What is expensive, and not cached, are the renderers. When Xamarin adds the ability to cache renderers, that's when the perf really improves.

  • ChaseFlorellChaseFlorell CAInsider, University mod
    edited January 2017

    @BrianLagunas said:
    @ChaseFlorell Actually, that doesn't do what you think it does. There is no real benefit to caching the XAML pages. Creating the XAML pages is relatively cheap. What is expensive, and not cached, are the renderers. When Xamarin adds the ability to cache renderers, that's when the perf really improves.

    Oh I know, but it doesn't stop developers from doing it. And IF they do re-use a page like that and the framework cleans up things like Behaviors, they'll be stuck with issues that they don't expect. My preference is to still clean it up manually, but have a cleaner mechanism within the framework for invoking the cleanup.

  • BrianLagunasBrianLagunas USInsider ✭✭✭✭

    Oh I know, but it doesn't stop developers from doing it.

    So true!

  • I have been chasing the memory leak for 4 hrs... each navigation has a 30k memory leak.

    I have a basic prism page and view model. Nothing in it. I continuously call:

    return ns.NavigateAsync("/" + pm.DestPage(), pm.BuildParam(), true);

    Each navigation leaks 30k. It does release the undelying view model and page, but somewhere in prism/ android is holding the 30k leak.

    Another leak is in the Listview itself. When there is a livstview.header bound to your view model, the view model never gets release, so a leak of your view model.

    Has anyone seen this ?

  • mostafa90mostafa90 USMember ✭✭
    edited August 2017

    @CarlosAlvarez.0353 Were you able to find a resolution? I am also facing the extra 30K memory leak :neutral: not sure how can i get rid of that.

  • ThrogarThrogar Member ✭✭

    Any improvements on this?

    I have an application that needs to run for hours and it leaks memory and eventually crashes.

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    @Throgar said:
    Any improvements on this?

    I have an application that needs to run for hours and it leaks memory and eventually crashes.

    "Improvement" on what? Its not the framework. Our company has a suite of apps that run around the clock on a fleet of trucks. Its not the eco-system.

    Its your code. Using resources that aren't managed by .NET is usually the first place to look. Graphic and bitmap items that you are cleaning up... creating outside of using blocks so they don't clean themselves up... objects you're loose track of and not destroying... etc.

  • ThrogarThrogar Member ✭✭

    @ClintStLaurent Hm, thanks for the insight.

Sign In or Register to comment.