On Aug 23, 2012, at 4:18 AM, mcleodia <[email protected]> wrote:
> Sorry, I meant the stacktrace I originally provided in the first post, which
> appears to point the finger at windowManager.DefaultDisplay.GetMetrics() and
> something going bad internally within the java world when this method was
> called.
It's not something "going bad...within the java world." Java's fine; it's
something going bad in the Mono world.
Mono for Android attempts to provide object identity; in the following code,
`a` and `b` are the same instance, and the exception is never thrown:
var a = context.ApplicationContext;
var b = context.ApplicationContext;
if (!object.ReferenceEquals (a, b))
throw new InvalidOperationException ();
The above is true because it would be borderline insane to do otherwise. ;-)
HOWEVER, in order to provide the above desired semantics, internally we
basically have a Dictionary<IntPtr, object> mapping JNI handles to object
wrapper instances, and when e.g. context.ApplicationContext is accessed we
invoke the Java Context.getApplicationContext() method and check to see if the
returned JNI handle is registered in the mapping. If it is, we return the
associated instance.
The problem happens when things get "messed up", which you can do deliberately
(if inadvisedly):
JNIEnv.DeleteGlobalRef (a.Handle);
var d = a.FilesDir;
In the above, we've explicitly deleted the gref associated with `a`. `a`
doesn't know that you've done this, so when you invoke the Context.FilesDir
property `a` will be using an invalid gref handle. What will happen? It depends
on the Android version; on v4.0+ you'll get a Dalvik VM error about using an
invalid gref (followed by app crash+exit). Pre-v4.0 it'll probably work,
because gref values are direct pointers to the Java instance.
Regardless, doing the above is a Bad Idea™. Don't do that.
So lets assume no one is doing anything as crazy/evil/stupid as calling
JNIEnv.DeleteGlobalRef(a.Handle). Is there any other way for things to get
screwed up "by accident"?
Sure: multithreading. If thread T1 calls Dispose() on an instance while thread
T2 is using the same instance, it's entirely possible that T2 will be using an
invalidated or invalid gref because T1 just mutated the same instance.
This also falls under the Don't Do That mantra: modifying shared instance
variables between threads is generally ill advised unless the types are known
to be thread safe or locking is used. The issue here is that it's easier to run
across shared instances, as unless you _know_ (via documentation) that a Java
method is creating a new instance, there's little/no way of knowing whether
you're getting a new instance that you can safely dispose.
> I just wanted to verify that stacktrace was an accurate indicator of the
> exact moment of failure...
Yes, it should be an accurate indicator.
- Jon
_______________________________________________
Monodroid mailing list
[email protected]
UNSUBSCRIBE INFORMATION:
http://lists.ximian.com/mailman/listinfo/monodroid