Как освободить ссылку из 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;
        }
    }
Другие вопросы по тегам