2

問題のあるコードをこの関数 (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 GB のマシンを持っています。)

上記の関数がスタックをオーバーフローするのはなぜですか? tail 再帰的に書かれていませんか?

よろしくお願いします。

4

2 に答える 2

5

OutOfMemoryException通常、RAMの容量とは何の関係もありません。コードが32ビットプロセスとして実行されるため、最大3GBで取得できる可能性があります。ただし、64ビットに切り替えると、実際にその量のメモリが必要であり、例外が何らかのバグによって引き起こされていない場合にのみ問題が解決します。

于 2013-01-14T17:31:05.027 に答える
5

これは末尾再帰の問題ではないと思います。もしそうなら、 . のStackOverflowException代わりにOutOfMemoryException. マシンに 16GB のメモリが搭載されていても、プログラムが実行されているプロセスはより少ない量のメモリに制限される可能性があることに注意してください。IIRC、.NET フレームワークのバージョンと OS のバージョンの組み合わせによっては 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 フレームワークの一部のバージョンと OS バージョンの CLR メモリ制限に関する詳細を含む以前の質問へのリンクです:単一の .NET プロセスにメモリ制限はありますか?

于 2013-01-14T17:26:28.703 に答える