[mono-android] VM full error

Jonathan Pryor jonp at xamarin.com
Fri Apr 13 03:57:51 UTC 2012

On Apr 12, 2012, at 8:02 PM, King Coffee wrote:
> I'm using the following code to allocate an image file to a ImageView control, with instance name: image.
> Bitmap bitmap = BitmapFactory.DecodeFile(matches[0]);
> image.SetImageBitmap(bitmap);

I've tried to expound upon this [0, 1], and I'm probably still not being clear enough, so let's flip the question around...

When _shouldn't_ you call Dispose()?

You shouldn't call dispose when the runtime type is a C# type, the instance has a peer held in Java code, and Java peer will be re-entering managed code.

Every Java.Lang.Object subclass has a corresponding (generated) Java peer type [1]. When you create an instance of the Java.Lang.Object subclass, you also create an instance of the Java peer type, and the Java peer and managed instance are associated with each other. Calling Dispose() breaks the association.

The problem with breaking the association is that once broken, if the Java peer re-enters managed code, a new Managed Callable Wrapper (MCW) will be instantiated, and a new mapping between the Java peer and the new MCW will be created. If you had any instance state, it will be "lost", which can be quite confusing. (Or you'll get an exception because the MCW type doesn't provide an (IntPtr, JniHandleOwnership) constructor...)

Note that this only really applies to C# types. If you're only dealing with Java types, you can dispose of the managed wrapper with (near) impunity; a new wrapper will be create if (when) the Java instance is (re-)exposed to managed code.

That is the fact with Bitmap: BitmapFactory.DecodeFile() will _never_ return C# type that contains C# instance state. Consequently, there's no need to ever preserve the association (unless you're storing `image` as a class member), so you can kill the mapping as soon as you're done with it:

	using (Bitmap bitmap = BitmapFactory.DecodeFile(matches[0]))

The result of the above is that only Java code will refer to the Bitmap instance, so when your code later changes the image's bitmap, Android will be able to quickly release the Bitmap instance.

> I tried to dispose of the control's context as follows: image.Context.dipose(), image.CacheDir.dispose(). 

That won't hurt, but it won't really help either. As mentioned above, if there isn't a wrapper for a Java instance, one will be created when the Java instance enters managed code, so the next time you call `image.Context` you'll simply get a new wrapper. (If you have an e.g. Dictionary<Context, object> you'll likely invalidate your keys if you do that, too. Care must be taken.)

> But, do I real need to dispose of container control, image? and reassign it?

I don't think you'll need to dispose of the container control, I imagine that just disposing of the image will be sufficient.

 - Jon

[0] http://docs.xamarin.com/android/advanced_topics/garbage_collection#Helping_the_GC
[1] http://docs.xamarin.com/android/advanced_topics/architecture#Managed_Callable_Wrappers

More information about the Monodroid mailing list