ConcurrentQueue содержит ссылку на объект или значение?исключение «недостаточно памяти» - PullRequest
3 голосов
/ 02 апреля 2012

Копируются ли объекты в 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);
}

Когда я запускаю это, яисключение Out of Memory через некоторое время.Я подумал, что это может быть из-за того, что сборщик мусора не собирает 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);

ИЯ проверил содержание пары элементов и увидел, что их содержание было другим!поэтому, если объекты, помещенные в очередь, копируются по значению, почему я сначала получил исключение «Недостаточно памяти»?

Ответы [ 2 ]

3 голосов
/ 02 апреля 2012

При вызове Enqueue в ConcurrentQueue<T> сохраняется только копия ссылки.Но эта ссылка строго удерживается, что означает, что она сохраняет фактический объект в памяти.Элемент не будет иметь права на сбор, пока ссылка не будет удалена из ConcurrentQueue<T>

. Причина, по которой вы не видите OutOfMemoryException при переключении на использование поля, заключается в том, что вы в корне изменили семантику

  • Исходный код: помещено N ссылок на N элементов в очередь, следовательно, он содержит N элементов в памяти
  • Измененный код: помещено N ссылок на 1 элемент в очередь, следовательно, он содержит 1элемент в памяти

Это значительно сократило объем памяти, который граф объектов ConcurrentQueue<T> держал в памяти, и предотвратило исключение.

Кажется, проблема здесь в том, что вы просто выравниваете элементы намного быстрее, чем обрабатываете их.До тех пор, пока это действительно так, в приложении будет не хватать памяти.Ваш код должен быть настроен так, чтобы он не попадал в это условие.

Примечание. Этот ответ написан в предположении, что BufferElement является class, а не struct.

Примечание2: Как отмечает Сервис в комментариях, вы можете рассмотреть возможность перехода наBlockingCollection<T>, поскольку он имеет несколько возможностей регулирования, которые могут вам помочь.

1 голос
/ 02 апреля 2012

Чтобы ответить на первый вопрос, ConcurrentQueue<T> содержит ссылку на содержимое.Это верно даже для типа значения T, потому что они помещаются в очередь при постановке в очередь.

Причина, по которой вы получили OOM для начала, заключается в том, что, вероятно, вы либо никогда не удаляете элементы из очереди (и поэтому да,Очередь будет поддерживать ссылки на них и поддерживать их, пока вы не удалите их из очереди), или вы не удаляете их из очереди достаточно быстро по сравнению с тем, как быстро вы их ставите в очередь.

В своем "исправлении" вы просто создаете толькоBufferElement один раз и непрерывно перезаписывайте его поля.Вы ставите в очередь один и тот же экземпляр класса снова и снова, что почти наверняка не соответствует желаемому поведению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...