Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 递归序列会泄漏内存吗?_F#_Memory Leaks_Sequence_Tail Recursion - Fatal编程技术网

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

F# 递归序列会泄漏内存吗?,f#,memory-leaks,sequence,tail-recursion,F#,Memory Leaks,Sequence,Tail Recursion,我喜欢递归地定义序列,如下所示: let rec startFrom x = seq { yield x; yield! startFrom (x + 1) } 我不确定像这样的递归序列是否应该在实践中使用。屈服似乎是尾部递归的,但我不能100%确定,因为它是从另一个IEnumerable内部调用的。在我看来,代码在每次调用时都会创建一个IEnumerable实例,而不关闭它,这实际上会使这个函数泄漏内存 此函数是否会泄漏内存?就这一点而言,它甚

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

let rec startFrom x =
    seq {
        yield x;
        yield! startFrom (x + 1)
    }
我不确定像这样的递归序列是否应该在实践中使用。
屈服
似乎是尾部递归的,但我不能100%确定,因为它是从另一个IEnumerable内部调用的。在我看来,代码在每次调用时都会创建一个IEnumerable实例,而不关闭它,这实际上会使这个函数泄漏内存

此函数是否会泄漏内存?就这一点而言,它甚至是“尾部递归”?

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

.NET应用程序不会以这种方式“泄漏”内存。即使您正在创建许多对象,垃圾收集也会将没有根的对象释放到应用程序本身


NET中的内存泄漏通常以应用程序中使用的非托管资源(数据库连接、内存流等)的形式出现。在这种情况下,创建多个对象然后放弃它们并不被视为内存泄漏,因为垃圾收集器能够释放内存。

它不会泄漏任何内存,它只会生成一个无限序列,但由于序列是IEnumerable,所以您可以枚举它们,而无需考虑内存问题。 递归发生在序列生成函数内部的事实并不影响递归的安全性。
请注意,在调试模式下,可能会禁用尾部调用优化以允许完全调试,但在发行版中不会出现任何问题。

我现在正在工作,所以我正在查看比Beta1稍新的位,但在发行模式下的框中,然后使用.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类示例
{
公共静态IEnumerable StartFrom(int x)
{
while(true)
{
收益率x;
x++;
}
}
}
(例如,我在我的盒子上运行了所有三个版本并打印了第一百万个结果,每个版本大约花费1.3秒+/-1秒)。(我没有做任何内存分析;可能我遗漏了一些重要的内容。)

简言之,我不会花太多时间思考这样的问题,除非你衡量并看到一个问题

编辑

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


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

>“不幸的是,我没有剖析器经验,所以我无法自己找到答案。”某种玩笑?一个人是如何获得经验的?我现在正在看NProf的记录,但希望得到更快的答案和技术解释。然而,垃圾收集并不能保证它将在何时收集这些对象。不,这不是内存泄漏实践,但也不是一个很好的内存节约实践。也有可能生成的IEnumerable可以被结构化,这样早期元素即使在不再需要之后也不适合进行垃圾收集,我认为这是一种泄露。“KVB——你是对的,但这与这个问题无关。不管使用什么算法,这都会造成内存问题。这取决于函数是否使用尾部递归。作为比较,等效的C#代码将在大约15000个整数后抛出StackOverflowException:静态IEnumerable startFrom(int x){yield return x;foreach(int y in startFrom(x+1))yield return y;}附录:经过快速测试后,F#代码看起来是尾部递归的。这是个好消息:)再次感谢你,布莱恩:)同时也为F#团队的其他成员表示敬意:)
public class CSharpExample
{
    public static IEnumerable<int> StartFrom(int x)
    {
        while (true)
        {
            yield return x;
            x++;
        }
    }
}