2

Running in API_14 emulator with WVGA800 screen with 24MB heap I am having problems with background images of my views, where it looks like the are drawables are not being released between view navigations and after 3 views are displayed an Out of memory exception occurs inflating a view.

The app starts with a SplashScreenActivity which has a 480x800 PNG as its background image to use for the startup splash screen. The app proceeds to navigate to its next view which also displays a new 480x800 px. The third screen navigation also contains 480x800 PNG and this when the out of memory error occurs. First I tried this with setting the background in the axml layout. then I tried alternative method of setting the background from code in the SplashScreenActivity.OnCreate() and the other two view OnCreate() methods. I read elsewhere that disposing the drawable release it from the mono vm in case this was the problem. Another trick which helped was to force a GC at the beginning of OnCreate() this left 12% of the heap free but this had limited success.

public class SplashScreenActivity: MvxBaseSplashScreenActivity
{
    public SplashScreenActivity() : base(Resource.Layout.SplashScreen) { }

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        using (var drawable = Resources.GetDrawable(Resource.Drawable.LoadingScreen))
            Window.SetBackgroundDrawable(drawable);
    }
}

And the second view

public class GameView : MvxBindingActivityView<GameViewModel>
{
    public GameView() { SoundBinding.GameView = this; }

    protected override void OnViewModelSet() { SetContentView(Resource.Layout.GameView); }

    protected override void OnCreate(Bundle bundle) 
    {
        GC.Collect();
        base.OnCreate(bundle);
        using (var drawable = Resources.GetDrawable(Resource.Drawable.GameScreenBackground))
            Window.SetBackgroundDrawable(drawable);
    }
}

After all this the App still runs out of memory on inflating a third similar view with background. Sometimes it will work, and then as screens cycle eventually it occurs. I looked at the heap dump on MAT and I can see two bitmapDrawables of 3.5M in size. I assume these are my two bitmaps. For the 2nd BitmapDrawable I can clearly see the view that is holding onto it. There is another bitmap still in memory but i can't see what its path to GC root is. This must be the first loaded PNG in the first SplashScreenActivity view. Here is its MAT Path to GC roots without weak refs. There is a weak ref holding it as well.

android.graphics.Bitmap @ 0x4134fb08 |           40 |     3,456,056
|- mBitmap android.graphics.drawable.BitmapDrawable @ 0x4134f568 |           64 |           136
|  |- mBackgroundDrawable com.android.internal.policy.impl.PhoneWindow @ 0x41356cc8 Native Stack  |          200 |         1,168
|  |- mBGDrawable com.android.internal.policy.impl.PhoneWindow$DecorView @ 0x41357560 Native Stack|          560 |           968
|  '- Total: 2 entries                                                                                 |              |              
|- mBitmap android.graphics.drawable.BitmapDrawable$BitmapState @ 0x4134f460                      |           40 |            40
 |  '- referent java.lang.ref.WeakReference @ 0x4134ff40 |           24 |            24
'- Total: 2 entries  |              |              

So question time. How do I ensure these drawables are released before the next view is inflated? Is it necessary to set the backgrounds in code rather than the layouts of the views? Do I need to unbindDrawables() by setting callback to null as seen here Drawable vs Single reusable Bitmap better with memory? ? I investigated the OnDestroy() overide of the views, but I found these where not being called before the new view is created. When navigating from one view to another is there away to ensure a view is destroyed and would this help release my resources before the next view is inflated.

Any advice on how better manage these resources in my app would be much appreciated.

Community
  • 1
  • 1
mdev
  • 131
  • 7

1 Answers1

1

Is there a simple sample app you can post anywhere that can reproduce this behaviour? Can you reproduce the same problem in a non-Mvvm app? In a non-MonoDroid Java app?

It feels like you are possibly seeing a leak at either the Android or the MonoDroid layer. I believe that all the views in the Conference app use Window.SetBackgroundDrawable and I haven't had problems reported there. (Possibly my image is smaller?)

As a workaround, one thing you could try is to override the OnPause and OnResume methods within the Activity Lifecycle in order to clear and reset the background drawable.

However, this is only a workaround... I think working through to a full solution would be worthwhile here.

Stuart
  • 66,722
  • 7
  • 114
  • 165
  • I have a sample app for you to look at that crashes. How can I share the repo with you. Can I send the repo address to you be email? – mdev Nov 11 '12 at 18:31
  • Is the Conference sample working for you? With backgrounds? If the conference sample is crashing for you, then please post details of your setup (e.g. Mac or PC? Android SDK? MonoDroid version number?) If the conference sample is working, then can you work out the difference between it and your app? If not, then please do post a link to your repo. – Stuart Nov 11 '12 at 20:17
  • I can't get the conference app to build for android, WP works fine. I was actually going to post a separate question regarding it. I get lots build error around maps like Error 24 package com.google.android.maps.ItemizedOverlay does not exist com.google.android.maps.ItemizedOverlay.OnFocusChangeListener D:\dev\vs\GitHub\MvvmCross\Sample - CirriousConference\Cirrious.Conference.UI.Droid\obj\Debug\android\src\mono\com\google\android\maps\ItemizedOverlay_OnFocusChangeListenerImplementor.java 8 42 Cirrious.Conference.UI.Droid Any idea how to fix this? – mdev Nov 11 '12 at 21:08
  • I'm definitely not answering that length of question in a comment. By all means do post a new question - or search for similar error messages. Sure we'll get it solved :) – Stuart Nov 11 '12 at 21:26
  • Cool - let me know if that shows the same leaks - or if it shows the same leaks after making the images as big as they are in your repo... then maybe also look at a non-mvvmcross project too - maybe this is a generic monodroid and/or android thing? – Stuart Nov 11 '12 at 22:02
  • Well it doesnt show the leaks runnning in a similar emulator. But I'd say this is because it only loads the one background resource. I can see the free memory is low so if it did load a second background it would probably fail. Rather than start to modify it, can you just look at the simple example I prepared here. bit.ly/TD02Jp its a bitbucket repo. It will quickly show you the error by the time you click through 3rd view. Run in API14 WVGA800 emulator. – mdev Nov 12 '12 at 11:18
  • I have GC.Collects commented out but you can add them back if you like. As far as I can see they don't free up the drawables. see http://http://mono-for-android.1047100.n5.nabble.com/Memory-Leak-with-Background-Image-td5165833.html – mdev Nov 12 '12 at 11:18
  • I can look at this when not at work... Is it possible for you to create a quick non-Mvx sample - does that leak too? If it does, then someone from Xamarin will need to assist... – Stuart Nov 12 '12 at 11:39
  • Well it looked like it was leaking from declaring backgrounds in the axml only, so i guess that would indicate a deeper problem. And possibly easier to replicate with a non-MVX sample. Ill look into this. I moved the setting of backgrounds into view code to see if it would help by disposing them manually. – mdev Nov 15 '12 at 14:17
  • If leaking when axml only... then it might even be an Android level issue - good luck! Sorry I can't help more... – Stuart Nov 15 '12 at 14:51