gpt4 book ai didi

c# - ConcurrentQueue 持有对象的引用或值? "out of memory"异常

转载 作者:行者123 更新时间:2023-11-30 15:39:50 25 4
gpt4 key购买 nike

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

我不明白任何场景。

解释:

我这样定义了一个 ConcurrentQueue:

// BufferElement is a class I created
private ConcurrentQueue<BufferElement> _bufferQueue;

我有一个被调用很多次的函数,它的目的是将一个元素排入队列:

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 中被引用,所以我将函数更改为:

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 任务管理器中的内存判断也不打算得到异常。

现在我认为问题已经解决了,因为当我将对象放入队列时,只有对对象的引用被发送到队列,但我担心队列中的所有元素都引用同一个对象,所以我检查了另一个线程中的另一个函数,它的作用是:

    // while bufferQueue is not empty do the following
BufferElement bufferElement = null;
bufferQueue.TryDequeue(out bufferElement);

然后我检查了几个元素的内容,发现它们的内容不同!所以如果排队到队列中的对象是按值复制的,为什么我一开始会遇到内存不足异常?

最佳答案

当您调用 EnqueueConcurrentQueue<T> 中仅存储了引用的副本.但是这个引用是强烈持有的,这意味着它确实将实际引用的对象保留在内存中。在从 ConcurrentQueue<T> 中删除引用之前,该元素将不符合收集条件

您没有看到 OutOfMemoryException 的原因当您切换到使用字段时是因为您从根本上改变了语义

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

这显着减少了内存量 ConcurrentQueue<T>对象图保存在内存中并阻止了异常。

这里的问题似乎是您简单地将元素排队比处理它们要快得多。只要这种情况成立,您最终就会在应用程序中耗尽内存。您的代码需要进行调整,以免遇到这种情况。

注意:这个答案是假设 BufferElement 写的是 class而不是 struct .

注意 2:正如 Servy 在评论中指出的那样,您可能需要考虑切换到 BlockingCollection<T>因为它有一些节流功能可以帮助您。

关于c# - ConcurrentQueue 持有对象的引用或值? "out of memory"异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9981637/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com