ConcurrentQueue持有对象的引用或值? “内存不足";例外 [英] ConcurrentQueue holds object's reference or value? "out of memory" exception

查看:280
本文介绍了ConcurrentQueue持有对象的引用或值? “内存不足";例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

排队到ConcurrentQueue的对象是复制到队列还是仅复制到它们的引用?

Is objects enqueued to a ConcurrentQueue are copied to the queue or just their references?

我不了解任何情况.

说明:

我这样定义了一个ConcurrentQueue:

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);
}

运行此命令后,一段时间后会出现内存不足"异常.我认为可能是因为垃圾收集器未收集bufferElement,因为它仍在bufferQueue中被引用,所以我将功能更改为:

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);
}

我没有得到异常,也不想通过Windows任务管理器中的内存来判断一个.

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?

推荐答案

调用Enqueue时,仅引用的副本存储在ConcurrentQueue<T>中.但是此引用被严格保留,这意味着它确实将实际引用的对象保留在内存中.在从ConcurrentQueue<T>

When you call Enqueue only a copy of the reference is stored in the ConcurrentQueue<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 the ConcurrentQueue<T>

切换到字段时未看到OutOfMemoryException的原因是因为您从根本上更改了语义

The reason you didn't see an OutOfMemoryException when you switched to using a field is because you fundamentally changed the semantics

  • 原始代码:将对N个元素的N个引用推入队列,因此将N个元素保留在内存中
  • 更改后的代码:将N个对1个元素的引用推入队列,因此它在内存中保留1个元素

这大大减少了ConcurrentQueue<T>对象图在内存中保留的内存量,并防止了异常.

This 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.

注意:编写此答案的前提是BufferElementclass而不是struct.

Note: This answer is written assuming BufferElement is a class and not a struct.

注意2:正如Servy在评论中指出的那样,您可能要考虑切换到BlockingCollection<T>,因为它具有一些限制功能,可能会对您有所帮助.

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.

这篇关于ConcurrentQueue持有对象的引用或值? “内存不足";例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆