Как освободить ссылку из ConcurentQueue для элемента, исключенного из параллельной очереди с TryDequeue
Я использую 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 ответ
См. Комментарии к принятому ответу здесь: Использование 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
, но эта вещь крошечная.
Я обращаюсь с использованием try..catch..Наконец рисунок. Использование последнего шаблона для установки вашей переменной в значение null - это правильный путь. Точка обработки возвращается в раздел finally, и вы можете освободить там неиспользуемые ресурсы. Я создаю программное обеспечение для торговли, и оно должно быть чистым и без утечек памяти!!!! Удачи!
static public ionDESK.Response.GenericResponse<object> RunScript(StrategyInput e)
{
var r = new ionDESK.Response.GenericResponse<object>();
try
{
r = e.ExecuteStrategy();
return r;
}
catch (Exception ex)
{
r.Errors.Add(ex.Message + " ExecuteStrategy " + ex.StackTrace);
return r;
}
finally
{
// When it returns...free resource
r = null;
}
}