我已将有问题的代码隔离到此函数(使用 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
。但我的系统内存消耗仅为 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/