我有一个简单的TCP服务器,可以监听连接客户端,而且看起来很简单
let Listener (ip:IPAddress) (port:int32) =
async {
let listener = TcpListener(ip, port)
listener.Start()
_logger.Info(sprintf "Server binded to IP: %A - Port: %i" ip port)
let rec listenerPending (listener : TcpListener) =
async {
if not (listener.Pending()) then return! listenerPending listener // MEMMORY LEAK SOURCE
printfn "Test"
}
listenerPending listener |> Async.Start
}
看起来很简单,但是我有一个内存泄漏问题:当它等待连接时,它会像糖果一样吞噬RAM。
我想它与递归函数有关,但不知道该怎么做才能稳定它。
答案 0 :(得分:6)
问题是您的listenerPending
函数不是尾部递归的。这有点违反直觉-但是return!
关键字不同于中断当前执行的命令式“ return”,而是对其他可以尾部递归的函数的调用(与{{1 }},如果位置正确,则永远不会。
为说明起见,请考虑以下内容:
do!
这实际上打印了从0到10的数字!这是因为let rec demo n =
async {
if n > 0 then return! demo (n-1)
printfn "%d" n
}
demo 10 |> Async.RunSynchronously
之后的代码在递归调用完成后仍会执行。您的代码结构类似,除了循环永远不会终止(至少不够快)之外。您可以通过删除return!
之后的代码(或将其移至return!
分支)来解决此问题。
此外,值得注意的是,您的代码并不是真正的异步-您没有任何非阻塞等待。您可能应该这样做而不是循环:
else