簡體   English   中英

try / catch塊中的F#MailboxProcessor內存泄漏

[英]F# MailboxProcessor memory leak in try/catch block

在John Palmer在評論中指出明顯錯誤后進行了更新

以下代碼導致OutOfMemoryException

let agent = MailboxProcessor<string>.Start(fun agent ->

    let maxLength = 1000

    let rec loop (state: string list) i = async {
        let! msg = agent.Receive()

        try        
            printfn "received message: %s, iteration: %i, length: %i" msg i state.Length
            let newState = state |> Seq.truncate maxLength |> Seq.toList
            return! loop (msg::newState) (i+1)
        with
        | ex -> 
            printfn "%A" ex
            return! loop state (i+1)
    }

    loop [] 0
)

let greeting = "hello"

while true do
    agent.Post greeting
    System.Threading.Thread.Sleep(1) // avoid piling up greetings before they are output

如果我不使用try / catch塊,則錯誤消失了。

增加睡眠時間只會延遲錯誤。

更新2:我想這里的問題是該函數不再是尾遞歸,因為遞歸調用不再是最后一個要執行的調用。 對於具有更多F#經驗的人來說,將其解糖會很好,因為我確定這是F#代理中常見的內存泄漏情況,因為代碼非常簡單且通用。

解:

事實證明,這是一個更大問題的一部分: 如果在try / catch塊中進行了遞歸調用,則該函數不能為尾遞歸,因為如果引發異常,它必須能夠展開堆棧保存呼叫堆棧信息。

此處有更多詳細信息:

F#中的尾遞歸和異常

正確重寫的代碼(單獨的try / catch和return):

let agent = MailboxProcessor<string>.Start(fun agent ->

    let maxLength = 1000

    let rec loop (state: string list) i = async {
        let! msg = agent.Receive()

        let newState = 
            try        
                printfn "received message: %s, iteration: %i, length: %i" msg i state.Length
                let truncatedState = state |> Seq.truncate maxLength |> Seq.toList
                msg::truncatedState
            with
            | ex -> 
                printfn "%A" ex
                state

        return! loop newState (i+1)
    }

    loop [] 0
)

我懷疑問題實際上在這里:

while true do
    agent.Post "hello"

您發布的所有"hello"都必須存儲在某個位置的內存中,並且其推送速度遠快於printf的輸出速度

在這里查看我的舊帖子http://vaskir.blogspot.ru/2013/02/recursion-and-trywithfinally-blocks.html

  • 隨機字符,以滿足本網站規則*

基本上,返回之后所做的任何事情(例如try / with / finally / dispose)都將阻止尾部調用。

請參閱https://blogs.msdn.microsoft.com/fsharpteam/2011/07/08/tail-calls-in-f/

還有一些工作正在進行,以使編譯器警告缺少尾遞歸: https : //github.com/fsharp/fslang-design/issues/82

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM