c# - TPL 和内存管理

标签 c# .net multithreading performance locking

使用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/

相关文章:

c# - 主机不允许连接到此MySQL服务器错误,但我没有使用MySQL

.net - TeamCity代理缺少DotNetFramework4.0_x86,但不是吗?

.net - 向开源项目的源代码管理添加强名称 key 有任何安全问题吗?

multithreading - 线程监视器如何工作?

c# - asp.NET 4.0 + CSS 问题 : How to create a give a different effect for the current webpage on the menu?

c# - 在运行时保存并重新加载 app.config(applicationSettings)

c++ - 异步是否总是在 C++ 中使用另一个线程/核心/进程?

multithreading - Grails,线程,自动服务

c# - 在.net Project MVC 中实现数据访问层最佳实践

.net - WPF,设计器中的 'Object reference not set to an instance of an object'