Как освободить ссылку из ConcurentQueue для элемента, исключенного из параллельной очереди с TryDequeue - PullRequest
0 голосов
/ 30 января 2019

Я использую ConcurrentQueue (C #, ASP.NET Core) для хранения задач для загрузки больших файлов.У меня очень большое потребление памяти даже после того, как элементы удалены из параллельной очереди.Элементы не удаляются из памяти.

Я понимаю поведение ConcurrentQueue в ASP.NET Core, короче говоря: каждая группа из 32 элементов в параллельной очереди сохраняется в отдельном сегменте.Ссылки освобождаются для исключенных элементов только после того, как исключены все элементы из определенного сегмента, а не после вызова метода TryDequeue () для одного элемента.В моем случае это проблема, потому что у меня может быть очень большой объем памяти, если в худшем случае не очищаются 32 элемента, которые потенциально могут быть очень большими zip-файлами.Я даже не ожидаю, что в очереди будет одновременно более 32 элементов.

Даже если я извлекаю файлы и отправляю их отдельно, каждый файл / изображение внутри может быть сам по себе большим.Единственное, что для меня достаточно - это освободить ссылку на каждый снятый с производства товар, без дальнейшей откладывания.Возможно ли это и как?

Я пытался использовать StrongBox, рекомендуется в некоторых статьях:

ConcurrentQueue<StrongBox<Func<CancellationToken, Task>>> 
workItems = new ConcurrentQueue<StrongBox<Func<CancellationToken, Task>>>();

// Enqueuing:
this.workItems.Enqueue(new StrongBox<Func<CancellationToken, Task>>(workItem));

// Dequeuing:
workItems.TryDequeue(out var workItem);
return workItem.Value;

Это не помогло в моем случае.Память не была освобождена.Я не знаю, моя проблема связана с тем, что я посылаю ссылку на функцию в очередь, и она каким-то образом хранится в памяти.Одним из параметров этой функции является конкретный файл для загрузки.Другие - просто строки.

В заключение я хотел бы позаботиться об освобождении памяти для элемента после или во время вызова метода TryDequeue ().Возможно ли это и как?

1 Ответ

0 голосов
/ 31 января 2019

См. Комментарии к принятому ответу здесь: Использование ConcurrentQueue.

Идея состоит в том, что вы можете обнулить свойство Value StrongBox.Таким образом, ваш код становится:

// Dequeuing:
workItems.TryDequeue(out var workItem);
var returnValue = workItem.Value;
workItem.Value = null; // see below
return returnValue;

Устанавливая workItem.Value = null, вы удаляете ссылку, которую StrongBox держит на элемент.Поэтому, как только ваш код сделан с его использованием, больше нет ссылок на элемент, и его можно собрать.Конечно, очередь продолжает содержать ссылку на StrongBox, но эта вещь крошечная.

...