Frank Liu
Frank Liu

Reputation: 1586

struct/value type memory allocation and deacllocation

Recently, I read Jon Skeet's Blog talking about C# object footprint and overhead. I wrote the following code to replicate his experiment.

class Pixel
{
    private byte _r;
    private byte _g;
    private byte _b;
    public int x { get; set; }
    public int y { get; set; }

    public System.Windows.Media.Color Color
    {
        get { return System.Windows.Media.Color.FromRgb(_r, _g, _b); }
    }
}

static void Main(string[] args)
{        
    size = 1000;
    var array3 = new Pixelsize];
    before = GC.GetTotalMemory(true);
    for (int i = 0; i < size; i++)
    {
       array3[i] = new Pixel();
    }
    after = GC.GetTotalMemory(true);
    Console.WriteLine("Pixel is {0} bytes", (after - before) / size);
}

So far so good, the program reports "Pixel is 15 bytes", which is 8 bytes base + 4 bytes + 1 + 1 + 1 = 15 bytes.

Then I wanted to know: Does a struct instance has the same overhead as a class instance does. So I changed Pixel to a struct.

struct Pixel
{
    private byte _r;
    private byte _g;
    private byte _b;
    public int x { get; set; }
    public int y { get; set; }

    public System.Windows.Media.Color Color
    {
        get { return System.Windows.Media.Color.FromRgb(_r, _g, _b); }
    }
}

Now, the program reports "Pixel is 0 bytes". Stepping into the code, I found that after is same as before. So struct is a value type, it is allocated from the stack. Right? Except, when I check the registers "ESP" does not change at all. So it is not allocated from the stack??

Looking at the TaskManager the memory usage of the demo program is increased by 8000 bytes after allocation. Where is this 8000 bytes coming from?

Lastly, since GC is unwared of the memory allocation, how can I deallocate this memory? I tried to put the allocation code inside a block and hoping when array3 goes out of scope, these memory will be released. However, the memory usage did not change. Am I getting a memory leak here?

static void Main(string[] args)
{        
   {
    size = 1000;
    var array3 = new Pixelsize];
    before = GC.GetTotalMemory(true);
    for (int i = 0; i < size; i++)
    {
       array3[i] = new Pixel();
    }
    after = GC.GetTotalMemory(true);
    Console.WriteLine("Pixel is {0} bytes", (after - before) / size);
  }
  //Expect the memory to be released here, but nothing happened. 
}

Upvotes: 1

Views: 163

Answers (1)

Vikas Gupta
Vikas Gupta

Reputation: 4465

  1. When you allocate an Array of reference types, inside a function.. Reference to the array itself may be stored on pre-allocated stack frame (i.e. 4/8 bytes for 32/64 bit). The actual allocation for 1000 elements is on the heap, again 4/8 bytes per element. Further, Instances of class are allocated as you call new Pixel(), and kept alive because their reference gets stored in the array.

  2. When you change it to an Array of value types, inside a function.. Reference to the array itself may be stored on pre-allocated stack frame (i.e. 4/8 bytes for 32/64 bit). The actual allocation for 1000 elements is on the heap, size of x bytes per element, where x is the size of the value type. Any value assigned to an element of array, gets copied, every byte.. Nothing is referenced by the array element.

Since you allocate the array of value types, before calling before = GC.GetTotalMemory(true);, before and after do not see any difference in allocation.

Put another way, in case of classes, allocation is at line array3[i] = new Pixel(); (on the heap) but in case of sruct, allocation is at line var array3 = new Pixel[size]; For the struct, new Pixel(); uses a little space on stack, but then you copy that value to the pre-allocated space for the array in the heap... and most likely reuse that stack space with each iteration.

It may be easier to think about the whole thing, if you think about array of int instead of array of Pixel.. Except for their difference in size, the mechanism between int and Pixel (defined as struct) will be the same.

Upvotes: 2

Related Questions