Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When happens to value types when they're removed from a collection?

Suppose I have some simple struct like this:

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

Then let's say I have a collection of instances of this structure:

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

As I understand value types versus reference types, value types are allocated on the stack, so a value type object is cleared from memory once the function instantiating said object terminates. This means that in the following code:

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

    weightedInts.Add(wint);
}

a copy of the local variable wint is added to weightedInts whereas the local variable itself is removed from memory after AddWeightedIntToList is completed.

First of all: is this correct?

Secondly, where does this copy of wint get stored? It can't be on the stack, since then it would be gone once the function completed (right?). Does this mean that the copy is stored on the heap along with weightedInts? And is it garbage collected after being removed, as if it were an instance of a reference type?

It's certainly possible that this question is answered in an article somewhere, in which case, a link to that article would be a totally acceptable answer. I just haven't had any luck finding it.

like image 722
Dan Tao Avatar asked Oct 05 '09 19:10

Dan Tao


2 Answers

First of all: is this correct?

Yes. The original is "gone" once the scope ends.

Secondly, where does this copy of wint get stored? It can't be on the stack, since then it would be gone once the function completed (right?). Does this mean that the copy is stored on the heap along with weightedInts? And is it garbage collected after being removed, as if it were an instance of a reference type?

Your instance of List<WeightedInt> creates an array on the heap. You're assigning a portion of that array a copy of your value type when you "add" it to the list. The value is saved on the heap, as part of an array (internal to the List class).

When your weightedInts member goes out of scope, it will become unrooted, and eligible to be garbage collected. At some point after that, the GC will run, and will release the memory associated with it's internal array, thereby freeing the memory associated with your copy of wint.


Edit:

Also, when you call:

weightedInts.Remove(wint);

A few things happen (with List<T>).

First, the list finds the index of the FIRST instance of your value type that equals wint. It then calls RemoteAt(index).

The RemoveAt(index) method basically marks that the internal size is one smaller, then checks the index you're removing. If it's in the middle of the list, it actually copies ALL of the value type instances up one element using Array.Copy, to "shrink" the list. It then zeros out the memory at the end of the array.

The array itself doesn't shrink, so no memory is released by removing elements. If you want to reclaim this memory (or even make it eligible for freeing by the GC), you need to call List<T>.TrimExcess().

like image 148
Reed Copsey Avatar answered Oct 23 '22 13:10

Reed Copsey


It is a common misconception that value types are always allocated on the stack.

The example you just showed is a perfect example of value types getting allocated on the heap.

like image 33
Dan Herbert Avatar answered Oct 23 '22 12:10

Dan Herbert