Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the value of a C# decimal stored on the heap even when it is a local variable?

Question

Is the value of a C# decimal stored on the heap when it is a local variable?

What I (believe to) know

  • The decimal struct has 16 bytes.
  • The value of a local variable of type ValueType is stored on the stack, and decimal inherits from ValueType.
  • On a 32bit system, the reference memory space is only 4 bytes big; with reference memory space I mean the boxes below labelled for example baz or bar enter image description here

    Image source.

  • For ValueTypes, that's where the value is stored; for reference types, that's where either null or the reference to the heap memory location is stored.

How can the value of a decimal, which is 16 bytes big, be stored on the stack at all where there are only 4 bytes available on a 32bit system?

Where did my thinking go wrong?

What I have read

  • Memory in .NET - what goes where - Jon Skeet
  • Arrays, heap and stack and value types - Stackoverflow
  • Do value types (Integer, Decimal, Boolean, etc…) inherit from Object? - Stackoverflow
  • And other articles on the Internet...
like image 943
Lernkurve Avatar asked Oct 20 '15 13:10

Lernkurve


People also ask

What is the value of a c?

The speed of light c = 299792458 m/s ≅ 3 × 108 m/s.

What is the value of c the speed of light?

The speed of light traveling through a vacuum is exactly 299,792,458 meters (983,571,056 feet) per second. That's about 186,282 miles per second — a universal constant known in equations as "c," or light speed.

What is the c in physics?

The speed of light in vacuum, commonly denoted c, is a universal physical constant that is important in many areas of physics. The speed of light c is exactly equal to 299792458 metres per second (approximately 300000 km/s or 186000 mi/s).


1 Answers

How can the value of a decimal, which is 16 bytes big, be stored on the stack at all where there are only 4 bytes available on a 32bit system? Where did my thinking go wrong?

Your thinking went wrong somewhere along the lines of "a 32 bit reference fits into 4 bytes" and concluding from that "the stack is 4 bytes long". The stack is by default a million bytes long; if the runtime decides to put a decimal variable (or value) on the stack then it reserves 16 of those million bytes.

It is good that you are thinking about how computers work under the hood, but of course do not forget that the C# team has worked hard to make a language where you don't have to care whether variables are on the stack or the heap. You have to be writing some very advanced programs for it to matter; I have never written a line-of-business C# program where I needed to worry about stack vs heap and I've been writing C# programs for 10+ years.

UPDATE:

I've updated the image to illustrate that I don't think the entire stack was 4 bytes long but only the one reference "memory box".

OK, great. So again, let's suppose a reference is four bytes, which on some machines it is. If the runtime needs to put a reference on the stack, it reserves four bytes on the stack. There is no requirement that the stack be reserved in four-byte chunks. It can be reserved in chunks of any size.

So I will update my explanation. You went wrong when you assumed "a reference is four bytes, therefore the stack can only be reserved in four-byte chunks". Any number of bytes can be reserved on the stack, from zero up to a million.

(Please don't try to reserve a million; bad things will happen. There's a reason why the .NET guidelines say to make structs that are 16 bytes or less!)

Now, for performance reasons on some architectures the runtime might attempt to reserve stack memory so that each chunk is aligned to four-byte boundaries. Some hardware is really slow if data is misaligned. But this is a level of detail that you almost never need to worry about in C#.

UPDATE again:

Here's another way to think about it. Suppose we have two normal local variables that are 4-byte ints:

int x;
int y;

That gets two chunks of memory that are four bytes each. Now suppose we have a struct:

struct S 
{ 
    public int x; 
    public int y; 
}

and we make a local variable:

S s;

That is exactly the same as before. We have two variables on the stack, and those variables are named s.x and s.y. Putting a struct on the stack is neither more nor less than putting all the field variables that are in the struct on the stack.

YET ANOTHER UPDATE:

Another thing that might be confusing you is that there is another kind of temporary storage called "registers" that are also used to store local variables, and registers really genuinely are only four bytes long. (Except for the ones which are 8, but let's not go there.) How is a 16 byte struct stored in a register? It isn't. The runtime simply doesn't put big structs into registers.

like image 166
Eric Lippert Avatar answered Sep 29 '22 14:09

Eric Lippert