1

I understand(not completely why, though) that instances of primitive types such as int, float are stored on the stack and are not heap allocated. But I am a bit confused about how arrays of primitive types are stored and accessed. I have this question because System.Array is a reference type. And reference types are heap allocated.

int[] integers = {1,2,3,4,5};

How are these individual integers stored and accessed on the memory?

gprasant
  • 15,589
  • 9
  • 43
  • 57

3 Answers3

10

Your "understanding" is flawed, basically. Value type values are sometimes stored on the stack - but not when part of an array or any other heap-based object. It's unfortunate that some people choose to make such a blanket statement around value types living on the stack, which then confuses others :(

Besides, the stack/heap distinction is an implementation detail...

See my article on memory for some more details, but definitely read Eric Lippert's blog post (linked in the previous paragraph) for more philosophical considerations. (Read his other posts on value types for even more information.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
10

You have discovered the reason why the statement "value types are always stored on the stack" is obviously wrong. The truth is that the type of the object being stored is irrelevant to where it is stored. The correct rule is that values with short lifetimes are stored in storage from the short-term "stack" and values with long lifetimes are stored in storage from the long-term "heap".

When you put it that way, it is practically a tautology. Obviously short-lived stuff is allocated from the short-term store, and long-lived stuff is allocated from the long-lived store! How could it be otherwise? But when you put it that way, clearly the type is irrelevant except insofar as the type gives you a hint about the lifetime.

The contents of an array of ints is potentially long-lived, so the ints are allocated from the long-term store. The contents of a local variable of type int is typically short-lived, so it is typically allocated from the short-lived store.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    @Eric: So the allocations are based on some predefined guidelines of short/long life of variables? If something turns out to be the other way around, is it reallocated to the other type of storage (i.e. from stack to heap, or vice versa)? – Joan Venge Oct 17 '11 at 20:05
  • 2
    @JoanVenge: Correct. For example, a local variable is usually short-lived. (By "short lived" I mean "does not live beyond the time when the method that needed the storage returns normally or throws.") But if a local variable is in an iterator block, is a closed-over local of a lambda, or is in an async method, it could be used *after* the method completes normally. Therefore those locals are allocated off of the long-term store. *Instances* of reference type might live a long time, so they go on the long-term store. *References* to those instances might be short-lived though! – Eric Lippert Oct 17 '11 at 20:31
  • 2
    In theory we could also notice that an instance of a reference type does in fact not live past the end of a method, and allocate it on the stack. In practice, we do not actually perform this optimization. – Eric Lippert Oct 17 '11 at 20:33
  • @Eric Would that be a compiler optimization or a JIT optimization? And does it relate to escape analysis? (I assume it would require some in-depth knowledge of the internals of the object, since it could be keeping itself alive through any number of ways.) – dlev Oct 17 '11 at 20:50
  • @EricLippert This means that the ONLY theoretical difference between value and reference type instances is the way their data is passed around beyond the original method boundaries? Everything else is implementation detail and is subject to change? – Konstantin Oct 18 '11 at 06:13
  • @Konstantin normal value types are non nullable. And you can't use them in certain situations(reference conversions aren't possible on them). But in theory they could be allocated on the heap. A C# to JVM compiler might do such a thing. – CodesInChaos Oct 18 '11 at 10:05
  • @Konstantin: The difference between reference types and value types is that reference types are *copied by reference* and value types are *copied by value*. That's why they're called "value types" and "reference types". Obviously that cannot change; if we started passing value types by reference, they'd cease to be value types! Everything else is an implementation detail. Storage can be allocated wherever the runtime thinks is best -- on the stack, in registers, on the heap, and so on. – Eric Lippert Oct 18 '11 at 13:45
  • @EricLippert if we assume that value types getting stored on a heap, does it not required to be boxed? Say in case of int[100] array? How about when i pass int[2000] items as an argument? I guess till the run time just passes it as reference right? What happens in case of params method? If i pass Method(1,2,3,....5000) to it? Still same way? – Zenwalker Oct 20 '11 at 05:40
  • @zenwalker: You have got it **completely backwards.** You seem to think that "a value type that is stored on the heap must be boxed" when in fact it is the opposite: a value type that is boxed must be stored on the heap. You are reasoning "if it is raining then the streets are wet; the streets are wet, therefore it must be raining". That doesn't follow at all. Why on earth would you have to box a value type just because it is on the heap? You have to box a value type *when it is being stored in a storage location of reference type*. – Eric Lippert Oct 20 '11 at 07:17
  • @EricLippert aaaaaaa now i got your point. All the books or articles i have read so far may be conveyed the message that when you wish to store some thing on heap it must be boxed. And if i am not wrong, for reference type additional 2 bytes of points are stored and they obviously are on heap - From Jeffreys book. So i thought to store on any thing on heap, it must have had 2 extra bytes and thus should be boxed. – Zenwalker Oct 20 '11 at 08:08
1

Array itself is always a reference type, so it's stored on heap. Elements of an array are stored on heap too, but always in a contiguous block of memory.

Łukasz Wiatrak
  • 2,747
  • 3
  • 22
  • 38