System.OutOfMemoryException для хвостовой рекурсивной функции
Я выделил проблемный код для этой функции (которая использует класс Membership ASP.NET):
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
после точно 5626
итерации h1
, Но потребление памяти моей системы только на 20 percent
, (У меня очень мощный аппарат на 16 ГБ.)
Почему вышеупомянутая функция должна переполнять стек? Не написано ли хвост рекурсивно?
Заранее спасибо за помощь.
2 ответа
Я не думаю, что это проблема хвостовой рекурсии - если так, то вы получите StackruException
вместо OutOfMemoryException
, Обратите внимание, что даже если у вас есть 16 ГБ памяти на вашем компьютере, процесс, в котором выполняется ваша программа, может быть ограничен меньшим объемом памяти. IIRC, это 3 ГБ для некоторых комбинаций версии.NET Framework и версии ОС - это объясняет, почему происходит сбой процесса, когда вы используете ~20% памяти (20% из 16 ГБ = 3,2 ГБ).
Я не знаю, насколько это поможет, но вы можете упростить свой код, чтобы избежать создания ненужных последовательностей:
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_
РЕДАКТИРОВАТЬ: Вот ссылка на предыдущий вопрос с подробной информацией об ограничениях памяти CLR для некоторых версий.NET Framework и версий ОС: существует ли ограничение памяти для одного процесса.NET
OutOfMemoryException
обычно не имеет никакого отношения к объему оперативной памяти, которая у вас есть. Вы получите его на ~3 ГБ, скорее всего, потому что ваш код работает как 32-битный процесс. Но переключение на 64-разрядную версию решит вашу проблему только в том случае, если вам действительно нужно столько памяти, а исключение не вызвано какой-либо ошибкой.