f# - 尾递归函数的 System.OutOfMemoryException

标签 f# asp.net-membership tail-recursion tail-call-optimization

我已将有问题的代码隔离到此函数(使用 ASP.NET 的 Membership 类):

let dbctx = DBSchema.GetDataContext()
let rec h1 (is2_ : int) (ie2_ : int) : unit =
    match is2_ >= ie2_ with
    | true ->
        let st2 = query {
            for row in dbctx.Tbl_Students do
            where (row.Id = is2_)
            head}
        let l2 =
            Membership.FindUsersByEmail (st2.Email_address)
            |> Seq.cast<_>
            |> Seq.length
        match l2 >= 1 with
        | true -> 
            ()
        | false ->
            Membership.CreateUser (st2.Email_address, password, st2.Email_address)
            |> ignore
        h1 (is2_ - 1) ie2_
    | false ->
        ()

h15626 次迭代之后,我得到了一个 System.OutOfMemoryException。但我的系统内存消耗仅为 20%。 (我有一台非常强大的 16 GB 机器。)

为什么上面的函数会溢出栈?不是递归写tail吗?

预先感谢您的帮助。

最佳答案

我认为这不是尾递归问题——如果是这样,您将得到一个 StackOverflowException 而不是 OutOfMemoryException。请注意,即使您的机器中有 16GB 的内存,您的程序在其中执行的进程也可能仅限于较小的内存量。 IIRC,对于 .NET Framework 版本和操作系统版本的某些组合,它是 3GB——这可以解释为什么当您达到约 20% 的内存使用率(16GB 的 20% = 3.2GB)时进程崩溃。

我不知道它会有多大帮助,但您可以简化代码以避免创建一些不必要的序列:

let dbctx = DBSchema.GetDataContext()
let rec h1 (is2_ : int) (ie2_ : int) : unit =
    if is2_ >= ie2_ then
        let st2 = query {
            for row in dbctx.Tbl_Students do
            where (row.Id = is2_)
            head }
        let existingUsers = Membership.FindUsersByEmail st2.Email_address
        if existingUsers.Count < 1 then
            Membership.CreateUser (st2.Email_address, password, st2.Email_address)
            |> ignore

        h1 (is2_ - 1) ie2_

编辑:这是指向上一个问题的链接,其中包含有关某些版本的 .NET 框架和操作系统版本的 CLR 内存限制的详细信息:Is there a memory limit for a single .NET process

关于f# - 尾递归函数的 System.OutOfMemoryException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14322940/

相关文章:

f# - 无限类型(又名递归类型)在 F# 中是不可能的吗?

f# - 将选项类型列表压缩为仅非无元素的最佳方法?

asp.net - 使用什么作为 ASP.NET 成员(member)后端? RavenDB 或 SqlServer

asp.net - 找回密码

arrays - 有没有一种简单的方法可以在 Fsharp 中将 byte [] 转换为 ReadOnlySpan<byte> ?

c# - 代表时间的最佳类(class)

asp.net-mvc - 获取所有角色 - ASP .Net Membership

Clojure:在 Erathosthene 筛中避免堆栈溢出?

python - 为什么尾递归优化比 Python 中的普通递归更快?

haskell - 删除列表中满足条件的第一个值