2

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

我得到System.OutOfMemoryException了. 但我系统的内存消耗仅为. (我有一台非常强大的 16 GB 机器。)5626h120 percent

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

在此先感谢您的帮助。

4

2 回答 2

5

我不认为这是一个尾递归问题——如果是这样,你会得到 aStackOverflowException而不是OutOfMemoryException. 请注意,即使您的机器中有 16GB 的内存,您的程序正在执行的进程也可能仅限于较小的内存量。IIRC,对于 .NET 框架版本和操作系统版本的某些组合,它是 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 内存限制的详细信息:单个 .NET 进程是否存在内存限制

于 2013-01-14T17:26:28.703 回答
5

OutOfMemoryException通常与您拥有的 RAM 数量没有任何关系。您最有可能以大约 3 GB 的速度获得它,因为您的代码作为 32 位进程运行。但是,如果您确实需要那么多内存并且异常不是由某些错误引起的,那么将其切换到 64 位只会解决您的问题。

于 2013-01-14T17:31:05.027 回答