5

私がstructこのような単純なものを持っているとしましょう:

public struct WeightedInt {
    public int value;
    public double weight;
}

次に、この構造のインスタンスのコレクションがあるとしましょう。

List<WeightedInt> weightedInts = new List<WeightedInt>();

値型と参照型を理解しているので、値型はスタックに割り当てられるため、値型オブジェクトをインスタンス化する関数が終了すると、値型オブジェクトはメモリからクリアされます。これは、次のコードでは次のことを意味します。

void AddWeightedIntToList(int value, double weight) {
    WeightedInt wint = new WeightedInt();
    wint.value = value;
    wint.weight = weight;

    weightedInts.Add(wint);
}

ローカル変数のコピーwintがに追加されweightedIntsますが、ローカル変数自体は完了後にメモリから削除されますAddWeightedIntToList

まず第一に:これは正しいですか?

次に、このコピーはどこwintに保存されますか?関数が完了すると消えてしまうので、スタックに置くことはできません(右?)。これは、コピーが一緒にヒープに保存されることを意味しますweightedIntsか?そして、それは参照型のインスタンスであるかのように、削除された後に収集されたガベージですか?

この質問がどこかの記事で回答されている可能性は確かにあります。その場合、その記事へのリンクは完全に受け入れられる回答になります。私はそれを見つけることができませんでした。

4

2 に答える 2

7

まず第一に、これは正しいですか?

はい。スコープが終了すると、オリジナルは「なくなり」ます。

次に、この wint のコピーはどこに保存されますか? 関数が完了すると消えてしまうため、スタック上に置くことはできません (そうですか?)。これは、コピーが weightedInts と共にヒープに格納されるということですか? そして、参照型のインスタンスであるかのように、削除された後にガベージ コレクションされますか?

のインスタンスはList<WeightedInt>、ヒープ上に配列を作成します。リストに「追加」するときに、その配列の一部に値の型のコピーを割り当てています。値は配列の一部としてヒープに保存されます (List クラスの内部)。

weightedInts メンバーが範囲外になると、ルート化されなくなり、ガベージ コレクションの対象になります。その後のある時点で、GC が実行され、GC の内部配列に関連付けられているメモリが解放され、wint のコピーに関連付けられているメモリが解放されます。


編集:

また、あなたが呼び出すとき:

weightedInts.Remove(wint);

いくつかのことが起こります (でList<T>)。

最初に、リストは wint と等しい値の型の最初のインスタンスのインデックスを見つけます。次に、RemoteAt(index) を呼び出します。

基本的に、RemoveAt(index) メソッドは、内部サイズが 1 つ小さいことをマークしてから、削除するインデックスをチェックします。リストの途中にある場合は、Array.Copy を使用してすべての値型インスタンスを 1 つの要素に実際にコピーし、リストを「縮小」します。次に、配列の最後にあるメモリをゼロにします。

配列自体は縮小されないため、要素を削除してもメモリは解放されません。このメモリを再利用したい (または GC による解放の対象にしたい) 場合は、 を呼び出す必要がありますList<T>TrimExcess ()。

于 2009-10-05T19:20:15.300 に答える
1

値型が常にスタックに割り当てられるというのはよくある誤解です。

先ほど示した例は、値型がヒープに割り当てられる完璧な例です。

于 2009-10-05T19:22:56.663 に答える