Shr*_*roy 2 f# tail-recursion asp.net-membership 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 ->
()
Run Code Online (Sandbox Code Playgroud)
System.OutOfMemoryException经过几次5626迭代后我才得到了h1.但我的系统的内存消耗仅为20 percent.(我有一台功能非常强大的16 GB机器.)
为什么上面的函数会溢出堆栈?是不是递归写尾?
在此先感谢您的帮助.
我不认为这是一个尾递归问题 - 如果是这样,你会得到一个StackOverflowException而不是一个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_
Run Code Online (Sandbox Code Playgroud)
编辑:这是上一个问题的链接,其中详细介绍了某些版本的.NET框架和操作系统版本的CLR内存限制:单个.NET进程是否有内存限制
OutOfMemoryException通常与您拥有的RAM量没有任何关系.你很可能得到~3 GB,因为你的代码是以32位进程运行的.但是如果你真的需要那么多内存并且异常不是由某些bug造成的,那么将它切换到64位只会解决你的问题.