Bug 21620 - ConditionalWeakTable invokes finalizer for value, even if the key object is still alive.
Summary: ConditionalWeakTable invokes finalizer for value, even if the key object is s...
Status: RESOLVED FEATURE
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler ()
Version: 4.12.4
Hardware: PC Windows
: Normal normal
Target Milestone: ---
Assignee: Marek Habersack
URL:
Depends on:
Blocks:
 
Reported: 2014-07-26 12:40 UTC by Vyacheslav Volkov
Modified: 2016-09-21 20:38 UTC (History)
4 users (show)

Tags: XATriaged
Is this bug a regression?: ---
Last known good build:


Attachments
Project to reproduce the bug (17.42 KB, application/x-zip-compressed)
2014-07-26 12:40 UTC, Vyacheslav Volkov
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and 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 Links.

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.

Related Links:
Status:
RESOLVED FEATURE

Description Vyacheslav Volkov 2014-07-26 12:40:46 UTC
Created attachment 7495 [details]
Project to reproduce the bug

Here's the code to reproduce the bug:

public class ObjectWithFinalizer
{
    public bool Finalized { get; private set; }

    ~ObjectWithFinalizer()
    {
        Finalized = true;
    }
}

[Activity(Label = "ConditionalWeakTableBug", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    private static readonly ConditionalWeakTable<object, object> WeakTable =
        new ConditionalWeakTable<object, object>();

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

        SetContentView(Resource.Layout.Main);

        var button = FindViewById<Button>(Resource.Id.MyButton1);
        button.Click += ButtonOnClick;

        button = FindViewById<Button>(Resource.Id.MyButton2);
        WeakTable.Add(button, new ObjectWithFinalizer());
    }

    private void ButtonOnClick(object sender, EventArgs eventArgs)
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        var button = FindViewById<Button>(Resource.Id.MyButton2);
        var value = (ObjectWithFinalizer) WeakTable.GetValue(button, key => null);
        if (value != null && value.Finalized)
            throw new InvalidOperationException();
    }
}
Comment 1 Parmendra Kumar 2014-07-28 09:38:16 UTC
We have checked with the attached project and observing 'System.InvalidOperationException' at line 47 in MainActivity.cs file. Here is the screencast of the same: http://www.screencast.com/t/qhMwTfcLMX

Please review the screencast and let us know if you are encountering the same problem.

If problem appears to be different as described in screencast, then please provide us the exact test steps to reproduce the issue. 

Environment: 
=== Xamarin Studio ===

Version 5.2 (build 384)
Installation UUID: 917f9508-3cad-494a-8fd9-cc9e3683ecc5
Runtime:
	Microsoft .NET 4.0.30319.34014
	GTK+ 2.24.22 (MS-Windows theme)
	GTK# 2.12.25

=== Xamarin.Android ===

Version: 4.12.6 (Business Edition)
Android SDK: D:\SDKndk\AndroidSDK\android-sdk
	Supported Android versions:
		2.1   (API level 7)
		2.2   (API level 8)
		2.3   (API level 10)
		3.1   (API level 12)
		4.0   (API level 14)
		4.0.3 (API level 15)
		4.4   (API level 19)
Java SDK: C:\Program Files\Java\jdk1.6.0_31
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) Client VM (build 20.6-b01, mixed mode)
Comment 2 Vyacheslav Volkov 2014-07-28 11:00:42 UTC
Yes, I am experiencing the same problem, finalizer was called, but the object is still alive.
Comment 3 Parmendra Kumar 2014-07-28 12:33:47 UTC
As per the comment 2, Marking as confirmed.
Comment 4 Marek Habersack 2016-09-21 20:38:35 UTC
The behavior described by OP is not a bug. The documentation for ConditionalWeakTable (https://msdn.microsoft.com/en-us/library/dd287757(v=vs.110).aspx) states:

  The ConditionalWeakTable<TKey, TValue> class differs from other collection 
  objects in its management of the object lifetime of keys stored in the 
  collection. 
  Ordinarily, when an object is stored in a collection, its lifetime lasts until
  it is removed (and there are no additional references to the object) or
  until the collection object itself is destroyed. However, in the 
  ConditionalWeakTable<TKey, TValue> class, adding a key/value pair to the 
  table does not ensure that the key will persist, even if it can be reached 
  directly from a value stored in the table (for example, if the table contains 
  one key, A, with a value V1, and a second key, B, with a value P2 that 
  contains a reference to A). Instead, ConditionalWeakTable<TKey, TValue> 
  automatically removes the key/value entry as soon as no other references 
  to a key exist outside the table.

The very last sentence states the reason for behavior in OP. The code in the provided solution does not keep any reference to the button that handles the click. Instead, the only reference is stored in the ConditionalWeakTable and inside the OnCreate method. OnCreate, however, returns long before the ButtonOnClick method is called and by this time its reference to the button no longer exists. Thus, as per the last sentence of the quoted documentation, the object is finalized. If you want to make sure the object is live you have to make 'button' an instance variable of the activity.