f# - 递归序列会泄漏内存吗?

标签 f# memory-leaks sequence tail-recursion

我喜欢递归地定义序列如下:

let rec startFrom x =
    seq {
        yield x;
        yield! startFrom (x + 1)
    }

我不确定在实践中是否应该使用这样的递归序列。 yield!似乎是尾递归,但我不是 100% 确定,因为它是从另一个 IEnumerable 内部调用的。从我的角度来看,代码在每次调用时都会创建一个 IEnumerable 实例而不关闭它,这实际上也会使该函数泄漏内存。

这个函数会泄漏内存吗?就此而言,它甚至是“尾递归”吗?

[编辑添加]:我正在用 NProf 摸索答案,但我认为获得关于在 SO 上实现递归序列的技术解释会很有帮助。

最佳答案

我现在正在工作,所以我正在查看比 Beta1 稍新的位,但是在我的机器上处于 Release 模式,然后使用 .Net Reflector 查看编译后的代码,似乎这两个

let rec startFromA x =    
    seq {        
        yield x     
        yield! startFromA (x + 1)    
    }

let startFromB x =    
    let z = ref x
    seq {        
        while true do
            yield !z
            incr z
    }

在“发布”模式下编译时生成几乎相同的 MSIL 代码。它们的运行速度与此 C# 代码的运行速度大致相同:
public class CSharpExample
{
    public static IEnumerable<int> StartFrom(int x)
    {
        while (true)
        {
            yield return x;
            x++;
        }
    }
}

(例如,我在我的盒子上运行了所有三个版本并打印了百万分之一的结果,每个版本大约需要 1.3 秒,+/- 1 秒)。 (我没有做任何内存分析;我可能遗漏了一些重要的东西。)

简而言之,除非您衡量并看到问题,否则我不会为这样的问题考虑太多。

编辑

我意识到我并没有真正回答这个问题......我认为简短的回答是“不,它不会泄漏”。 (有一种特殊的意义,其中所有“无限”IEnumerables(带有缓存的后备存储)“泄漏”(取决于您如何定义“泄漏”),请参阅

Avoiding stack overflow (with F# infinite sequences of sequences)

有关 IEnumerable(又名“seq”)与 LazyList 以及消费者如何急切地使用 LazyLists 以“忘记”旧结果以防止某种“泄漏”的有趣讨论。)

关于f# - 递归序列会泄漏内存吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1019945/

相关文章:

c# - F#'s async state machines the same as C#' 是 async 还是 go-lang 的 go 命令?

f# - 在 Xamarin Studio 中找不到 FSharp.Core

java - 如何找到代码中内存泄漏的地方?

ios - UIImageView ARC 内存泄漏

c# - 有没有比 System.Byte.Parse ("0xAA"更好的东西来获得 F# 和 C# 上的单个字节?

c# - F# 中的字典推导式(?)(从 C# 转换)

python - python中数据帧的序列长度

python - 如何在 sqlalchemy 中为我的主键列配置序列对象?

objective-c - 如何正确释放 UITabController

java - mongo 中的序列 - 可以依赖 findAndModify() 吗?