【问题标题】:Rx.Net memory leakRx.Net 内存泄漏
【发布时间】:2020-03-19 17:39:40
【问题描述】:

一个有趣的内存泄漏。有谁知道为什么?

foreach (int x in Enumerable.Range(0, 1_000_000)
    .Select(async i => i))
{
}

GC.Collect();
Console.WriteLine(GC.GetTotalAllocatedBytes()); // 1036542160

foreach (int x in Enumerable.Range(0, 1_000_000)
    .Select(async i => i))
{
}

GC.Collect();
Console.WriteLine(GC.GetTotalAllocatedBytes()); // 2072860704

foreach (int x in Enumerable.Range(0, 1_000_000)
    .Select(async i => i))
{
}

GC.Collect();
Console.WriteLine(GC.GetTotalAllocatedBytes()); // 3109160008

地点:

static class SelectAsync
{
    public static IEnumerable<TResult> Select<T, TResult>(
        this IEnumerable<T> source, Func<T, Task<TResult>> selector) =>
        source
            .ToObservable()
            .Select(value => Observable.FromAsync(() => selector(value)))
            .Concat()
            .ToEnumerable();        
}

【问题讨论】:

  • 您的示例表明,如果性能和资源的有效利用至关重要,那么反应式扩展可能不是该工作的正确工具。你可以用一个简单的循环和List&lt;TResult&gt; 来收集结果,只消耗一小部分 RAM 和 CPU 资源。

标签: c# linq system.reactive


【解决方案1】:

实际上没有内存泄漏。

GC.GetTotalAllocatedBytes 是在进程生命周期内分配的字节数。每次进行堆分配时,此计数器都会增加。

你想改用GC.GetTotalMemory

如果您看到测试值之间的差异,您会发现它们大致相同。

您会在测试中看到一些与内存压力相关的细微变化。

【讨论】:

  • 4,520,216; 8,726,544; 12,921,320; 17,116,528; 21,311,592...看起来它不断增长 4MB。
  • 我使用 TotalMemory 运行。我看到183320、183980、185276、186656、188276、187964、185516、185516、185516、186524、185060、185060、188048、185600、186080等
  • 我的进程内存配置文件似乎也支持这一点。
  • @DmitryNogin 你能告诉我你的结论是什么吗?
  • 开始使用IAsyncEnumerable&lt;T&gt;。将构建过程更新到 .NET Core 3.1 将会有一场斗争...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2013-01-20
  • 2011-10-31
  • 2019-08-10
  • 2013-06-24
  • 2011-03-22
  • 2015-04-20
相关资源
最近更新 更多