如果谓词为假,c# SkipWhile会泄漏内存

本文关键字:SkipWhile 泄漏 内存 谓词 如果 | 更新日期: 2023-09-27 18:14:37

// 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:好吧,愚蠢的东西是字符串。我忘记了,这是附加到一个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;
    }
}

如果谓词为假,c# SkipWhile会泄漏内存

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

如果你改变你的代码来独立处理每一行,你会看到你使用更少的内存:

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

您的错误不在SkipWhile上,当您在其中传递true时会导致它跳过每一行-不返回您的连接结果。

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