首页 > 解决方案 > 是否可以为 LINQ 使用自定义内存分配器?

问题描述

有没有办法为 LINQ 使用自定义内存分配器?

例如,当我打电话时:

someCollection.Where(x).SelectMany(y).ToList();

ToList()or这样的方法OrderBy()总是会创建一个新数组,所以会发生很多 GC。使用自定义分配器,我总是可以使用相同的列表,每次都会被清除和重新填充。我知道重用缓冲区可能会导致重入问题。

背景是,我的应用程序是一个游戏,而 GC 意味着口吃。请不要告诉我“改用 C++”或“不要使用 LINQ”,我知道 :)

标签: c#.netlinqmemory-management

解决方案


(尽管您要求不要反对它,但我认为这个答案可以帮助社区)

LINQ 是建立在 CLR 之上的工具,因此它使用 CLR 分配器,并且无法更改。你可以稍微调整一下,例如配置是否应该将 GC 周期卸载到后台线程,但你不能再进一步了。

LINQ 的目的是简单地为某些类别的问题编写代码,牺牲选择每个构建块的实现的自由(这就是我们通常选择 LINQ 的原因)。

但是,根据具体情况,LINQ 可能不是您最好的朋友,因为它的设计选择可能会与您的选择不符。如果在分析您的代码之后,您发现您有严重的性能问题,您应该首先尝试确定您是否可以隔离某些 LINQ 方法中的瓶颈,并查看您是否可以通过扩展方法滚动您自己的实现。当然,当 yuo 是主要呼叫者时,此选项是可行的,除非您设法滚动一些IEnumerable投诉。您需要非常幸运,因为您的实现应该遵守 LINQ 规则。特别是,由于您无法控制对象的操作方式,因此您无法在自己的代码中执行优化。关闭和延期执行对您不利。

否则,评论所建议的是唯一可行的选择:避免将 LINQ 用于该特定任务。

放弃 LINQ 的原因是它不是解决您需要的性能约束问题的正确工具。此外,正如评论中所述,(ab)使用 lambda 表达式显着增加了内存压力,因为创建了支持对象来实现闭包。

我们遇到了与您类似的性能问题,我们不得不重写某些慢速路径。在其他(罕见)情况下,预分配列表并通过 help.loading 加载结果AddRange


推荐阅读