Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
Mono organizations on
GitHub to continue tracking issues. Bugzilla will remain
available for reference in read-only mode. We will continue to work
on open Bugzilla bugs, copy them to the new locations
as needed for follow-up, and add the new items under Related
Our sincere thanks to everyone who has contributed on this bug
tracker over the years. Thanks also for your understanding as we
make these adjustments and improvements for the future.
Please create a new report on
Developer Community or GitHub with
your current version information, steps to reproduce, and relevant error
messages or log files if you are hitting an issue that looks similar to
this resolved bug and you do not yet see a matching new report.
Check out this code (on single view android template - hence the button.Text):
var tubo = new object();
var refx = new WeakReference(tubo);
tubo = null;
button.Text = refx.IsAlive.ToString();
After running it, I'd expect button to show False. But instead it is showing True.
It doesn't help if I do more collections in a loop.
@Miha, can you please create and attach a full, small, application that reproduces the issue as well as specify the Xamarin.Android version you are using and then reopen the bug, thanks!
Created attachment 22802 [details]
Sure, attached. Or you can simply create a new Single View Android app and paste the code into it. I'm running it on VS4A API 23 emulator.
And what's your Xamarin.Android version?
VS 15.2 with all the updates (26430.12)
Xamarin.Android SDK 184.108.40.206
the runtime does conservative stack scanning, so this sort of behavior is expected.
This doesn't happen in actual app code, so it's not a practical concern.
Rodrigo, can you elaborate.
Why is the behavior expected? I mean the object is gone or not at that point?
"This doesn't happen in actual app code, so it's not a practical concern."
What do you mean by "in actual app code"? It is happening in actual app code. Or did you mean that it doesn't happen in release configuration?
Anyway, here is my scenario. I was unit testing some code and checking whether objects were released properly. Since WeakReference doesn't look working reliable at this point, how can I check it?
The object, as you verified, is not gone.
When the object goes away is not deterministic and applications should not depend on it.
As you mentioned, you found the issue on an unit test that creates a scenario that doesn't exists on actual apps.
As how to test your code, assume WeakRefs work on normal setups, set them to null and check your invariants.
"When the object goes away is not deterministic and applications should not depend on it."
App doesn't depend on it. Just tests. But that is a sort of an app, isn't it :)
"As you mentioned, you found the issue on an unit test that creates a scenario that doesn't exists on actual apps."
OK, I'm still puzzled what exactly do you mean by "this doesn't exist on actual apps".
"As how to test your code, assume WeakRefs work on normal setups, set them to null and check your invariants."
Can you give me an example? Also what do you consider by a normal setup?
In your unit test, you create the WeakRef, set a local variable to null then call GC all from the same method, on an actual app, that would be a really weird thing do to.
What usually happens is one method creates the WeakRef, store it somewhere and return. Then later the GC would trigger due to allocation and that WeakRef would be null'd.
The problem here is two-fold. First, our GC conservatively scans the stack and second, our compiler eliminates redundant stores such as the one that does "tubo = null;".
Conservative stack scanning means the GC looks at the contents of the execution stack and assume everything can potentially be an object reference. This causes objects to be wrongfully retained because we don't scrub the stack at the start or end of a method execution. Normal execution naturally erases old values from the stack.
In your example, tubo is saved on the stack as it's used as argument on a call.
Eliminating redundant stores is a common optimization as they don't change program behavior.