Is the value of a C# decimal
stored on the heap when it is a local variable?
decimal
struct has 16 bytes.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
Image source.
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?
The speed of light c = 299792458 m/s ≅ 3 × 108 m/s.
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.
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With