MvvmCross / MvvmCross-AndroidSupport

Android support library packages for MvvmCross: The .NET MVVM framework for cross-platform solutions.
http://mvvmcross.com
15 stars 0 forks source link

Memory leak in ViewPager #241

Open fedotovsi opened 8 years ago

fedotovsi commented 8 years ago

I noticed memory leak in my project when I was using MvxFragmentStatePagerAdapter2. I tried all viewPager adapters and all of them have same problem, it seems MvxFragmentsPresenter doesn't recycle internal fragment views.

Steps to reproduce

1.Put some large byte array in PagerAdapter as private field

2.Start application, it can be your example

3.Navigate to ViewPager or ViewPagerState

4.Navigate to another fragment, e.g. Home

5.Repeat steps 3 and 4 several times

6.See in profile how will grow up memory allocation.

Expected behavior

ViewPager and ViewPagerAdapter to be destroyed with fragment view

Actual behavior

Someone has ref to ViewPager, so memory is grow up after each createView-destryoView cycle

Configuration

Version: 4.1.4

thefex commented 8 years ago

I don't think it's MvvmCross bug - I think this is Android bug. I have developed one application which used a lot of pages in ViewPager before MvvmCross support library came in. I've used standard Android view pager adapters and implemented Mvvm support by my own. I had same problems as you have described - unfortunately I was not able to fix that (redesigned a bit UI to avoid ImageViews in pager fragments). My ImageViews bitmaps weren't disposed correctly thus sometimes when I had a lot of pages with ImageViews my application crashed with OutOfMemoryException.

kjeremy commented 8 years ago

This is most likely the issue here: https://stackoverflow.com/questions/18977923/viewpager-with-nested-fragments.

Here's a workaround I used in a previous project:

using System;
using Android.App;
using Java.Lang;
using Java.Lang.Reflect;

namespace MinefieldManagement.Droid.Helpers
{
    /// <summary>
    /// Cleans up the Fragment's child fragment manager.
    /// It should be used on any fragment that uses ChildFragmentManager.
    /// </summary>
    public static class ChildFragmentCleanupHelper
    {
        public static void OnDetach(Fragment fragment)
        {
            // Fix nested fragment's being put into an invalid state.
            // See: https://stackoverflow.com/questions/18977923/viewpager-with-nested-fragments
            // See: https://stackoverflow.com/questions/15207305/getting-the-error-java-lang-illegalstateexception-activity-has-been-destroyed/15656428#15656428
            // See: https://code.google.com/p/android/issues/detail?id=42601
            try
            {
                Class fragmentClass = Class.FromType(typeof(Fragment));
                Field childFragmentManager = fragmentClass.GetDeclaredField("mChildFragmentManager");
                childFragmentManager.Accessible = true;
                childFragmentManager.Set(fragment, null);
            }
            catch (NoSuchFieldException e)
            {
                throw new InvalidOperationException(e.Message);
            }
            catch (IllegalAccessException e)
            {
                throw new InvalidOperationException(e.Message);
            }
        }
    }
}

Then in your fragment:

public override void OnDetach()
{
    base.OnDetach();

    ChildFragmentCleanupHelper.OnDetach(this);
}
thefex commented 8 years ago

@kjeremy that won't help with memory leaks as I have used that "trick" (it has just solved crashes for me)

kjeremy commented 8 years ago

@thefex Xamarin profiler?

fedotovsi commented 8 years ago

yes, I used Xamarin profiler. Thanks for your answers it seems the problem in Xamarin or Android, because fragment is destroying normally, the problem is in controls which are in there, I supposed during fragment destroying it will enter in Control.Dispose() and I tried it without MvxFragment and it works the same. So I clear my resources in OnDestroyView manually and it seems the best solution for now. I think issue can be closed, thanks for your support

kjeremy commented 8 years ago

@fedotovsi can you post your OnDestroyView code? I'm curious as to what you need to clear to make the leak go away. It may provide a clue. Did the profiler tell you what was kept alive?