On Apr 17, 2012, at 3:43 AM, Igor Russkih wrote:
> With original list of ~100 items, I'm getting overflow with just a couple of 
> device (or emulator) "flips":

Is this with Mono for Android 4.0.6 or the 4.1.0 alpha? In 4.1.0 we altered 
things so that when we hit a gref threshold we perform a collection 
automatically. It's still not a great thing to rely on -- the GC might be 
performed at the exact wrong time -- but could help with the gref limit.

Alternatively, you might try calling GC.Collect() from within OnCreate() to 
collect any garbage instances from the previous activity.

> Having a "settings" dialog with couple of Spinners (with > 200 items in 
> there) it'll overflow even on real device after a minute of "Flipping".

Indeed, things aren't perfect:

        
http://docs.xamarin.com/android/advanced_topics/garbage_collection#Helping_the_GC

While we're working on improving this where we can, many scenarios will still 
rely on developer help. :-)

> Notice, that aadapter.Dispose() doesn't help (although it should).

Not necessarily; `aadapter.Dispose()` will allow the managed ArrayAdapter to be 
collected (and free the associated gref), but it won't do anything about what 
`aadapter` references (in this case `jl`, and everything it contains).

You're using the Android.Widget.ArrayAdapter(Context, int, IList) constructor, 
which will construct a JavaList to contain the contents of the IList, which 
will result in a gref for each element within the list. If these are strings, 
it should be more efficient to instead use ArrayAdapter<string>:

        var aadapter = new ArrayAdapter<string>(Adapter.Activity, 
Android.Resource.Layout.SimpleSpinnerItem, jl.ToArray());

Note that for string and builtin types (int, etc.), using the string[] 
constructor instead of the IList<string> constructor will be more efficient.

> Is this a bug? Doing a workaround with:
> 
>                 var jl = new Android.Runtime.JavaList();
>                 foreach(var i in this.Items)
>                 {
>                     var js = new Java.Lang.String(i.ToString());
>                     jl.Add(js);
>                     js.Dispose();
>                 };

This workaround is the right idea, but wrong: given that you don't control when 
collections are performed, it's possible that the Java.Lang.String you create 
won't exist by the time you create the ArrayAdapter(). You should instead have 
a second foreach loop to call js.Dispose() after the ArrayAdapter constructor 
call.

> Mean its good to have a workaround, but I've lost a couple of hours to find 
> it (instead of doing what I should do - create the UI).

Sorry. :-(

I'll need to bump the priority of fixing scenarios like this...

> Another, more annoying issue (no workaround found so far):
> 
> In my views I have event listeners attached with
>     Click += ..
>     FocusChange += ..
>     TextChange += ..
> etc.
> Here is what I'm getting after couple of "flips":
> 
> W/dalvikvm( 4626):   468 of Lmono/android/text/TextWatcherImplementor; 12B 
> (468 unique)
> W/dalvikvm( 4626):    16 of Lmono/android/text/TextWatcherImplementor; 20B 
> (16 unique)
> W/dalvikvm( 4626):     1 of Lmono/android/app/Application; 12B
> W/dalvikvm( 4626):   468 of 
> Lmono/android/view/View/OnFocusChangeListenerImplementor; 12B (468 unique)
> W/dalvikvm( 4626):    17 of 
> Lmono/android/view/View/OnFocusChangeListenerImplementor; 20B (17 unique)
> W/dalvikvm( 4626):     1 of Lxxxxroid/SettingsActivity; 204B
> W/dalvikvm( 4626):     1 of Landroid/view/Window$LocalWindowManager; 20B
> W/dalvikvm( 4626):     1 of Lmono/android/view/View/OnKeyListenerImplementor; 
> 12B
> W/dalvikvm( 4626):   472 of 
> Lmono/android/view/View/OnClickListenerImplementor; 12B (472 unique)
> W/dalvikvm( 4626):    12 of 
> Lmono/android/view/View/OnClickListenerImplementor; 20B (12 unique)
> W/dalvikvm( 4626):     1 of Lfleux/controls/DoubleBufferedControl_HostView; 
> 228B
> W/dalvikvm( 4626):     1 of 
> Lmono/android/view/View/OnTouchListenerImplementor; 12B
> 
> All the views are disposed in onStop() for sure.
> Tried to remove listener delegates ( doing -=) but that doesn't help.

#facepalm. Oops. Yeah, that's a definite bug. :-/

The e.g. add_Click() handler calls SetOnClickListener() (hence the 
mono/android/view/View/OnClickListenerImplementor instances), but 
remove_Click() doesn't call SetOnClickListener(). Currently, the only way to 
collect this is to allow the entire View to be collected. (You could also call 
SetOnClickListener() yourself, but that will unfortunately break event 
registration -- another bug we ran across last night...)

> Doing also GC.Collect(0) in each onStart() - doesn't help.

That's unexpected. Does a full GC.Collect() collect it?

> I've already heard a comment "use real device and see no issues with 50000 
> gref limit".
> But IMHO that is something like saying "get a 4Gb device and don't care of 
> these memory leaks".

To a large degree, I agree. However, given the current model, if you have a 
View that _requires_ holding > 2000 grefs, there's no way to make that work on 
the emulator; hardware is the only workaround. (Can we change the current 
gref-based model? Yes. Timeframe? Unknown... :-(

 - Jon

_______________________________________________
Monodroid mailing list
[email protected]

UNSUBSCRIBE INFORMATION:
http://lists.ximian.com/mailman/listinfo/monodroid

Reply via email to