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
GitHub or Developer Community 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.
When dequeueing elements from a ConcurrentQueue<T>, the last element is still getting referenced by the queue until a new element is added.
Steps to reproduce:
1. Create a class that logs its creation and destruction (finalizer)
2. Add multiple instances of this class to the ConcurrentQueue.
3. Dequeue all of the instances from the queue and discard them by not assigning them to a variable.
4. Force GC collection (GC.Collect(), GC.WaitForPendingFinalizers())
5. All instances are collected.
5. Notice that the last instance has not been collected!
6. Set the queue reference to null
7. Force GC collection again
8. With the queue being collected, the last instance of the custom class is now also collected.
6. Add a new element to the queue
7. Force GC collection again
8. The old element is now properly collected (while the new one is now leaked :) )
This is a major problem, as code that depends on finalizers doesn't expect a queue to hold references to dequeued objects.
One example is a queue where System.Threading.Tasks get submitted. Those tasks propagate unobserved exceptions to the TaskScheduler's UnobservedTaskExceptionHandler, when they are garbage collected. However, due to this ConcurrentQueue issue, those exceptions don't get reported - or they get reported with a delay - depending on how extensively the queue is used.
The problem's source seems to stem from the early return statement in the "if (next == null)" branch of the TryDequeue implementation as seen by the assembly browser. In this case, this.head and this.tail are not properly updated.
Use a standard Queue with a lock :-) At least one can understand the code behind the standard queue, and the performance is enough for most cases anyway.
=== Xamarin Studio ===
Version 4.2.3 (build 60)
Installation UUID: 938751df-f7a5-457d-b87b-379763e0ada1
Mono 3.2.6 ((no/9b58377)
GTK+ 2.24.23 theme: Raleigh
Package version: 302060000
=== Apple Developer Tools ===
Xcode 5.1 (5084)
=== Xamarin.iOS ===
Version: 22.214.171.124 (Business Edition)
Build date: 2014-10-03 18:02:26-0400
=== Xamarin.Android ===
Version: 4.12.1 (Business Edition)
Android SDK: /Users/etankissling/Library/Developer/Xamarin/android-sdk-mac_x86
Supported Android versions:
4.3 (API level 18)
Java SDK: /usr
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462-11M4609)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode)
=== Xamarin.Mac ===
Xamarin.Mac: Not Installed
=== Build Information ===
Release ID: 402030060
Git revision: 30c4afc300c2a39ec5300851357ce02e49dd217e
Build date: 2014-03-05 22:09:33+0000
Xamarin addins: f8a9589b57c2bfab2ccd73c880e7ad81e3ecf044
=== Operating System ===
Mac OS X 10.9.2
Darwin Etans-MacBook-Pro.local 13.1.0 Darwin Kernel Version 13.1.0
Thu Jan 16 19:40:37 PST 2014
Thank you for the detailed bug report.
A pull request for this issue can be found here https://github.com/mono/mono/pull/1068.
Fixed in master 7c52a7bf5fe10f70b547b37f757a9ad022d29d1f.