【问题标题】:C# SkipWhile leaks memory if predicate is false如果谓词为假,C# SkipWhile 会泄漏内存
【发布时间】:2016-10-24 21:19:25
【问题描述】:
// C:\logs\AzureSDK.log is ~2.5GB file
IEnumerable<string> lines = File.ReadLines(@"C:\logs\AzureSDK.log").SkipWhile(line => false);

Console.WriteLine(string.Join("\n", lines));
return;

这显然 在我得到 OOM 之前不会返回迭代器并在内部分配内存。在SkipWhile 谓词中返回true 不会导致这种情况并按预期完成(对MB 执行期间的内存使用情况)

根据文档、方法签名和常识,SkipWhile 必须返回一个迭代器,而不是将所有数据加载到内存中。

机器信息

Microsoft Windows [Version 10.0.14393]
Target 4.5.2, AnyCPU, Release
VS 2015 Update 3
NET 4.6.01586

想法?我一定是在做一些愚蠢的事情,但不确定是什么

UPD:愚蠢的事情是我忘记的 string.Join,它附加到单个 StringBuilder 将所有行加载到内存中。

我还检查了 SkipWhile 来源,它显然非常好:

public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
    if (source == null) throw Error.ArgumentNull("source");
    if (predicate == null) throw Error.ArgumentNull("predicate");
    return SkipWhileIterator<TSource>(source, predicate);
}

static IEnumerable<TSource> SkipWhileIterator<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate) {
    bool yielding = false;
    foreach (TSource element in source) {
        if (!yielding && !predicate(element)) yielding = true;
        if (yielding) yield return element;
    }
}

【问题讨论】:

  • SkipWhile 确实返回一个枚举数。但是随后您使用string.Join 连接所有内容,因此最终将整个文件加载到内存中
  • 我知道我一定是个笨蛋,谢谢
  • 不漏,只是使用^_^
  • 问题是明显的编码错误的结果,并不反映标题/正文中说明的原始问题,因此令人困惑

标签: c# linq memory-leaks


【解决方案1】:

SkipWhile 确实返回一个枚举器。但随后您使用string.Join 连接所有内容,因此最终将整个文件加载到内存中。

如果您更改代码以独立处理每一行,您会发现您使用的内存要少得多:

foreach (var line in File.ReadLines(@"C:\logs\AzureSDK.log").SkipWhile(_ => false))
{
    Console.WriteLine(line);
}

【讨论】:

  • 我非常专注于最小化复制,以至于我完全忘记了显然创建一个 StringBuilder 并附加到它的连接。通过内存分析器确认并查看字符串。加入源
  • 我想是拖钓。尽管有时像这样的小东西可以隐藏在清晰的视线中,这很明显。无论如何投票结束,因为这是一个编程错误,而不是它打算成为的问题
  • 最好删除它,关闭你自己的问题没有意义
  • 因此无法将带有答案的问题标记为删除。
  • @KooKiz 是的,当我看到我的回答被赞成而你的回答被反对时,这很奇怪。
【解决方案2】:

您的错误不在 SkipWhile 上,当您传入 true 时,它​​会导致它跳过每一行 - 不会为您的加入返回任何结果。

string.Join 导致内存不足异常,因为它试图分配一个长度为 2.5gb 的字符串。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 2011-10-25
    • 2016-01-27
    • 2010-11-11
    • 2017-02-18
    • 1970-01-01
    相关资源
    最近更新 更多