System.OutOfMemoryException用于尾递归函数

我已经将有问题的代码隔离到了此函数(使用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 ->
        ()

h1 5626次迭代之后,我得到一个System.OutOfMemoryException 5626 。 但是我的系统内存消耗只有20 percent 。 (我有一个非常强大的16 GB机器。)

为什么上面的函数应该溢出栈? 它是不是递归地写尾?

在此先感谢您的帮助。


我不认为这是一个尾递归问题 - 如果是这样,你会得到一个StackOverflowException而不是一个OutOfMemoryException 。 请注意,即使您的计算机中有16 GB的内存,程序执行的过程可能会限制为较小的内存量。 IIRC,对于.NET框架版本和操作系统版本的某些组合,它的容量是3GB - 这可以解释为什么当内存使用量达到20%时(16GB = 20GB的20%),进程崩溃。

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

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内存限制的详细信息:是否有单个.NET进程的内存限制


OutOfMemoryException通常与您拥有的RAM数量无关。 你可以在〜3 GB之内得到它,这很可能是因为你的代码是以32位进程运行的。 但切换到64位只会解决你的问题,如果你真的需要那么多的内存和异常不是由一些错误引起的。

链接地址: http://www.djcxy.com/p/80575.html

上一篇: System.OutOfMemoryException for a tail recursive function

下一篇: Why isn't this F# inner function tail