これが初心者の質問なら申し訳ありませんが、私は確信する必要があります。
関数が呼び出されると、一時オブジェクトが作成される場合があり、そのオブジェクトのメモリ割り当ては終了時に解放されます。
私の質問は、関数がリストにマップされている場合、各関数呼び出しによって割り当てられたメモリはすぐに解放されますか、それともリスト全体が処理された後にのみ解放されますか?
これは例です。各関数呼び出し内に2つのオブジェクト(newListとnewRec)が作成されることを除いて、コードが具体的に行うことは意味がありません。
newListとnewRecに割り当てられたメモリは、各「反復」の後に解放されますか、それともList.mapの呼び出しが終了した後にのみすべてのメモリが解放されますか?
これはおそらく命令型言語のループで簡単に理解できるはずですが、F#コンパイラがそのような場合にどのように対処するかはわかりません。
type MyRecord = { AList: int list; Name: string }
let myRecord = { AList = [1..100]; Name = "SomeRecord" }
let foo (arec: MyRecord) i =
let newList = arec.AList |> List.filter (fun x -> x >= i)
let newRec = { arec with AList = newList }
List.sum newRec.AList
let res = [1..100] |> List.map (foo myRecord)
どちらでもない。F#には、ガベージコレクションに基づく自動メモリ管理があります。メモリのブロックが解放される原因は、構文上の条件ではなく、実行時の条件です。メモリのブロックは、到達不能になった後に解放されます。
現在のスコープ内の変数からオブジェクトを取得する方法がある場合、オブジェクトは到達可能です。関数のfoo
実行中、newList
およびnewRec
到達可能であるため、解放されません。関数が戻るとき、newList
およびnewRec
もはや直接到達可能ですが、どのような彼らが解放可能になることは、彼らはもはやされていないことである間接的に到達可能なのいずれか。次のバリエーションを検討してくださいfoo
。
let bar (arec: MyRecord) i =
let newList = arec.AList |> List.filter (fun x -> x >= i)
let newRec = { arec with AList = newList }
newRec.AList
がbar
戻ると、newRec
オブジェクトは到達できなくなりますがnewList
、関数によって返され、関数の呼び出し元が使用できるため、オブジェクトは到達可能です。
自動メモリ管理は、オブジェクトの寿命を気にする必要がないことを意味します。特に、解放されたオブジェクトにアクセスしようとすることは不可能です¹。構造上、オブジェクトにアクセスできれば、到達可能であるため解放されません。
の特定のケースではfoo
、への呼び出しがfoo
戻るとすぐに、それが作成したオブジェクトnewRec
とnewList
オブジェクトに到達できなくなります。これは、必ずしもすぐに解放されることを意味するわけではありません。遅くとも、次の完全なガベージコレクターの実行中に解放されます。到達不能なオブジェクトが解放されずに残る時間は、ガベージコレクターの品質の問題です。これは、メモリ使用量とパフォーマンスの間の妥協点です(GCを実行すると、収集されていないガベージがほとんど残らないが、CPU時間がかかります。GCを実行すると、CPU時間がほとんど消費されないが、収集されていないガベージがたくさん残ります)。
いずれにせよ、foo
を介して複数回呼び出しているという事実List.map
は、メモリ管理とは関係ありません。List.map
戻っても特別なことは何も起こりません。
¹アンマネージメモリを使用する他の言語で記述されたコードと対話する場合を除き ます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加