Is objects enqueued to a ConcurrentQueue are copied to the queue or just their references?
I don’t understand any scenario.
Explanation:
I defined a ConcurrentQueue like this:
// BufferElement is a class I created
private ConcurrentQueue<BufferElement> _bufferQueue;
I have a function which is called a lot of times and it’s purpsoe is to enqueue an element to the queue:
private void EnqueueElementToBuffer(string data, int moreData)
{
// the bufferElement constructor is setting data and moreData to it's fields.
BufferElement bufferElement = new BufferElement(data, moreData);
bufferQueue.Enqueue(bufferElement);
}
When I run this I get Out of Memory exception after a while. I thought it might be because the garbage collector does not collect the bufferElement because it is still has referenced in the bufferQueue, so I changed the function to this:
private void EnqueueElementToBuffer(string data, int moreData)
{
// _bufferElement is now a filed of the class
_bufferElement.Data = data;
_bufferElement.MoreData = moreData;
bufferQueue.Enqueue(_bufferElement);
}
And I didn’t get the exception, and wasn’t about to get one judging by the memory in the windows task manager.
Now I thought that the problam was solved because when I enqueued objects to the queue only the reference to the objects is cpoied to the queue, but I was afraid that all the elements in the queue are referencing to the same object, so I checked another function I have in another thread which what it does is:
// while bufferQueue is not empty do the following
BufferElement bufferElement = null;
bufferQueue.TryDequeue(out bufferElement);
And I checked the content of couple of elements and saw that their content was different! so if objects enqueued to the queue are copied by value why I got the Out of Memory exception at first?
When you call
Enqueueonly a copy of the reference is stored in theConcurrentQueue<T>. But this reference is strongly held which means it does keep the actual referred to object in memory. The element won’t be eligible for collection until the reference is removed from theConcurrentQueue<T>The reason you didn’t see an
OutOfMemoryExceptionwhen you switched to using a field is because you fundamentally changed the semanticsThis significantly reduced the amount of memory the
ConcurrentQueue<T>object graph was holding in memory and prevented the exception.It seems like the problem here is you are simply equeuing elements much faster than you are processing them. So long as this holds true you will eventually run out of memory in the application. Your code needs to be adjusted such that it won’t hit this condition.
Note: This answer is written assuming
BufferElementis aclassand not astruct.Note2: As Servy points out in the comments you may want to consider switching to a
BlockingCollection<T>as it has a few throttling capabilities which may help you.