gpt4 book ai didi

c# - TPL 和内存管理

转载 作者:行者123 更新时间:2023-12-03 12:51:25 29 4
gpt4 key购买 nike

使用Visual Studio Concurrency Visualizer我现在明白为什么切换到 Parallel.For 没有任何好处:只有 9% 的时间机器忙于执行代码,其余的时间为 71% 的同步和 17% 的内存管理(1).

检查下图中的所有橙色条纹,我发现总是涉及 GC (2)。

阅读完所有这些有趣的主题后...

.. 我是否正确地假设所有这些线程都需要使用单个内存管理对象,因此消除了在堆上分配对象的需要,我的场景将大大改善?比如使用结构体而不是类,数组而不是动态列表等等?

我需要做很多工作才能朝这个方向弯曲我的代码。只是想在开始之前确定一下。

enter image description here

最佳答案

从您的屏幕截图来看,内存分配似乎在等待 GC 完成时被阻止。有服务器和工作站GC模式,并且可以是并发的,也可以是非并发的,但所有选项都需要阻塞线程至少一段时间。我会更详细地检查您在 GC 上花费的频率和时间,以及 gen 0/1 和 2 运行的频率。

我相信每个线程都有一个单独的临时段用于分配,因此不需要同步分配,除非它需要一个新段,或者分配位于大对象堆上。但我找不到这方面的引用。

无论如何,您可能会从减少分配的数量和大小中受益。如果可能的话,使用对象池或内存池来重用内存。您还可能会受益于增加内存量并检查应用程序是否存在内存泄漏。对于内存的一般建议是应该有两种类型的分配:

  1. 仅存活很短时间的小型临时分配,例如在方法调用期间存活的临时对象。
  2. 在“应用程序”期间有效的任意大小的长期分配。

如果遵循这种模式,几乎所有垃圾都应该在 Gen 0/1 中收集,而第 2 代收集应该相当罕见。

如果您要分配许多小对象或大块内存,这也有点取决于。如果是前者,您可以考虑使用结构,因为它们是堆栈分配的。如果后者还需要考虑内存碎片,这也应该通过使用仅分配固定大小的内存块的内存池来改进。

编辑:

最简单的对象池可能是这样的:

public class ObjectPool<T> 
{
private ConcurrentBag<T> pool = new ConcurrentBag<T>();
public T Get(Func<T> constructor) => pool.TryTake(out var result) ? result : constructor();
public void Return(T obj) => pool.Add(obj);
}

这假设对象代表相同的资源,例如某个固定大小的字节数组。但也有现有的实现:

关于c# - TPL 和内存管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64256760/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com