如何使用 TryDequeue 从 ConcurentQueue 释放从并发队列中出队的项目的引用
How to release reference from the ConcurentQueue for the item dequeued from the concurrent queue with TryDequeue
我正在使用 ConcurrentQueue(C#,ASP.NET 核心)来保存上传大文件的任务。即使在项目从并发队列中出列之后,我的内存消耗也非常大。项目未从内存中清除。
我了解 ASP.NET Core 中 ConcurrentQueue 的行为,简而言之:并发队列中 32 个项目的每组都保存在单独的段中。仅在特定段中的所有项目都已出队后,才会释放已出队项目的引用,而不是在为单个项目调用 TryDequeue() 方法后。这对我来说是一个问题,因为如果在最坏的情况下有 32 个项目没有被清理,我的内存中可能会有非常大的数量,这可能是非常大的 zip 文件。我什至不希望队列中同时有超过 32 个项目。
即使我把文件解压出来单独发,里面的每个file/image也很大。唯一对我来说足够好的是发布每个出列项目的参考,而不会进一步推迟。这可能吗?如何实现?
我试过用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() 方法之后或期间处理项目的内存释放。这可能吗?如何实现?
在此处查看对已接受答案的评论:Usage of ConcurrentQueue<StrongBox<T>>。
我们的想法是,您可以使 StrongBox
的 Value
属性 为空。所以你的代码变成:
// Dequeuing:
workItems.TryDequeue(out var workItem);
var returnValue = workItem.Value;
workItem.Value = null; // see below
return returnValue;
通过设置 workItem.Value = null
,您将删除 StrongBox
对项目的引用。因此,一旦您的代码使用完它,就不再有对该项目的引用,并且可以收集它。当然,队列继续持有对 StrongBox
的引用,但那个东西很小。
我使用 Try..Catch..Finally 模式处理。使用最终模式将变量设置为 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;
}
}
我正在使用 ConcurrentQueue(C#,ASP.NET 核心)来保存上传大文件的任务。即使在项目从并发队列中出列之后,我的内存消耗也非常大。项目未从内存中清除。
我了解 ASP.NET Core 中 ConcurrentQueue 的行为,简而言之:并发队列中 32 个项目的每组都保存在单独的段中。仅在特定段中的所有项目都已出队后,才会释放已出队项目的引用,而不是在为单个项目调用 TryDequeue() 方法后。这对我来说是一个问题,因为如果在最坏的情况下有 32 个项目没有被清理,我的内存中可能会有非常大的数量,这可能是非常大的 zip 文件。我什至不希望队列中同时有超过 32 个项目。
即使我把文件解压出来单独发,里面的每个file/image也很大。唯一对我来说足够好的是发布每个出列项目的参考,而不会进一步推迟。这可能吗?如何实现?
我试过用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() 方法之后或期间处理项目的内存释放。这可能吗?如何实现?
在此处查看对已接受答案的评论:Usage of ConcurrentQueue<StrongBox<T>>。
我们的想法是,您可以使 StrongBox
的 Value
属性 为空。所以你的代码变成:
// Dequeuing:
workItems.TryDequeue(out var workItem);
var returnValue = workItem.Value;
workItem.Value = null; // see below
return returnValue;
通过设置 workItem.Value = null
,您将删除 StrongBox
对项目的引用。因此,一旦您的代码使用完它,就不再有对该项目的引用,并且可以收集它。当然,队列继续持有对 StrongBox
的引用,但那个东西很小。
我使用 Try..Catch..Finally 模式处理。使用最终模式将变量设置为 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;
}
}