F#异步递归调用中的内存泄漏

lob*_*ism 11 f# memory-leaks asynchronous tail-recursion

我很困惑为什么这个功能显示内存不断增加

let rec startRead1() = 
  async {
    do! Async.Sleep 1
    System.GC.Collect()
    let mem = System.GC.GetTotalMemory(true)
    printfn "%d" mem
    do! startRead1()
  }
Run Code Online (Sandbox Code Playgroud)

25676 36760 36840 36884 36928 36972 37016 37060 37104 37328 37362 37212 37456 37500 37544 37588 37632 37676 37720 37764 37808 37852 37896 37940 37984 38028 38072 38116 38160 38204 38248 38292 38336 38380 38424 38468 38512 38556 38600 38644 38688 38732 38776 38820 38864 38908 38952 38996 39040 39084 39128 39172 39216 ^ C按任意键继续...

[<EntryPoint>]
let main _ = 
  startRead1() |> Async.RunSynchronously
  0
Run Code Online (Sandbox Code Playgroud)

而这一个显示稳定的记忆

let rec startRead2() = 
  async {
    while true do
      do! Async.Sleep 1
      System.GC.Collect()
      let mem = System.GC.GetTotalMemory(true)
      printfn "%d" mem
  }
Run Code Online (Sandbox Code Playgroud)

同步版本也很稳定.

let rec startRead3() = 
  System.Threading.Thread.Sleep 1
  System.GC.Collect()
  let mem = System.GC.GetTotalMemory(true)
  printfn "%d" mem
  startRead3()
Run Code Online (Sandbox Code Playgroud)

我在没有附带调试器的发布模式下运行,FS 3.1,.NET 4.5.1.

Seh*_*cht 20

引自此处(文章末尾):

" 此外,F#async也存在问题(最常见的问题是必须使用尾递归函数return!而不是do!避免泄漏) "

  • Gah,现在如果只有FS电动工具能够快速找到我解决方案中的所有递归异步函数......至少我必须犯这个错误十几次!花了一天的时间将崩溃提炼到泄漏到异步到一个可重现的功能. (3认同)