2009-10-05 7 views
3

Supposons que j'ai quelques simples struct comme ceci:Quand arrive aux types de valeur quand ils sont retirés d'une collection?

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

Alors disons que j'ai une collection d'instances de cette structure:

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

Comme je comprends les types de valeurs par rapport aux types de référence, les types de valeur sont alloués sur la pile, de sorte qu'un objet de type valeur est effacé de la mémoire une fois que la fonction instanciant ledit objet se termine. Cela signifie que dans le code suivant:

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

    weightedInts.Add(wint); 
} 

une copie de la variable locale wint est ajouté à weightedInts alors que la variable locale elle-même est retirée de la mémoire après AddWeightedIntToList est terminée.

Tout d'abord: est-ce correct?

Deuxièmement, où cette copie de wint est-elle stockée? Il ne peut pas être sur la pile, puisqu'il serait alors parti une fois la fonction terminée (droite?). Est-ce que cela signifie que la copie est stockée sur le tas avec weightedInts? Et est-ce que le garbage est collecté après avoir été supprimé, comme s'il s'agissait d'une instance d'un type de référence?

Il est certainement possible que cette question soit traitée dans un article quelque part, auquel cas, un lien vers cet article serait une réponse totalement acceptable. Je n'ai juste pas eu de chance de le trouver.

+2

Les types de valeur ne sont PAS alloués sur la pile. Les variables locales de type valeur qui ne sont pas dans un bloc d'itérateur ou qui sont fermées par une fonction anonyme * peuvent être allouées sur la pile et sont souvent allouées sur la pile, mais ce n'est pas nécessaire. Ils pourraient être alloués sur le tas, ou ils pourraient être alloués dans des registres. –

+0

Si vous êtes intéressé par plus d'analyse de la fausseté "les types de valeur sont alloués sur la pile", voici deux articles que j'ai écrits sur le sujet: http://blogs.msdn.com/ericlippert/archive/2009/ 04/27/the-pile-is-a-implementation-detail.aspx et http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail- part-two.aspx –

Répondre

5

Tout d'abord: est-ce correct?

Oui. L'original est "parti" une fois la portée terminée.

Deuxièmement, où cette copie de wint est-elle stockée? Il ne peut pas être sur la pile, puisqu'il serait alors parti une fois la fonction terminée (droite?). Est-ce que cela signifie que la copie est stockée sur le tas avec weightedInts? Et est-ce que le garbage est collecté après avoir été supprimé, comme s'il s'agissait d'une instance d'un type de référence?

Votre instance de List<WeightedInt> crée un tableau sur le tas. Vous affectez une partie de ce tableau à une copie de votre type de valeur lorsque vous l'ajoutez à la liste. La valeur est enregistrée sur le tas, dans le cadre d'un tableau (interne à la classe List).

Lorsque votre membre weightedInts est hors de portée, il devient non raclé et peut être collecté. À un moment donné, le GC s'exécutera et libèrera la mémoire associée à son tableau interne, libérant ainsi la mémoire associée à votre copie de wint.


Edit:

Aussi, lorsque vous appelez:

weightedInts.Remove(wint); 

Quelques choses arrive (avec List<T>).Tout d'abord, la liste trouve l'index de la première instance de votre type de valeur qui est égale à wint. Il appelle ensuite RemoteAt (index). La méthode RemoveAt (index) marque essentiellement que la taille interne est une plus petite, puis vérifie l'index que vous supprimez. S'il est au milieu de la liste, il copie en réalité TOUTES les instances de type valeur d'un élément en utilisant Array.Copy, pour "réduire" la liste. Il zéros ensuite la mémoire à la fin du tableau.

Le tableau lui-même ne se rétrécit pas, donc aucune mémoire n'est libérée en supprimant des éléments. Si vous souhaitez récupérer cette mémoire (ou même la rendre admissible à la libération par le GC), vous devez appeler le List<T>. TrimExcess().

+0

De ce que vous dites, je peux conclure que la valeur ajoutée à 'weightedInts' sera collectée après que' weightedInts' sera hors de portée. Mais ce qui me reste obscur est ce qui lui arrive si j'appelle 'weightedInts.Remove (wint); '- reste-t-il en train de traîner jusqu'à ce que' weightedInts' soit récupéré? –

+0

Non. Je vais modifier pour clarifier. –

+0

Donc une liste d'ints serait stockée dans le tas et la seule allocation sur la pile serait le pointeur vers le tas pour le tableau? –

1

Il est souvent admis à tort que les types de valeur sont toujours alloués sur la pile.

L'exemple que vous venez de montrer est un exemple parfait de types de valeur alloués sur le tas.

Questions connexes