6

I know c#, like Java, translating the source into bytecode and run by VM, for C# case is CIL stored in assembly and executed by CLR. Developers scarcely need to care about where the variable is on stack or on heap(handled by GC) as c++, right?

Is their any quick and straightforward way to demonstrate that a variable is stored on stack or on heap? For example, if I tell someone the reference type variables are stored on heap or the local value type variable on stack(right?). How can I show that explicitly? In C++, I can get a variable's memory address and view its value stored in stack or heap memory by VS memory window.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Wason
  • 1,341
  • 1
  • 13
  • 26
  • One way is just to write a sample app and to take a process dump and load it up in windbg to poke around the stack vs heap. You could get all the address values you want then, but that's not a "proof". Any reason to not trust the c# spec and the JIT following through? – devshorts Jul 31 '14 at 03:26
  • Write a sample program,Hit Immediate window(ALT+I-Visual Studio).and then load SOS.(.load sos)..and then start exploring with !dumpheap.. – Rangesh Jul 31 '14 at 03:29
  • @devshorts I have changed the wording. – Wason Jul 31 '14 at 03:34
  • 2
    Please read [this](http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx) before you tell someone that value-typed local variables use the stack for storage. – Mike Zboray Jul 31 '14 at 03:38
  • please check here; http://stackoverflow.com/questions/4487289/memory-allocation-stack-vs-heap – Teoman shipahi Jul 31 '14 at 03:48

1 Answers1

22

Developers scarcely need to care about where the variable is on stack or on heap, right?

Right. The technique chosen for the storage is an implementation detail of the runtime.

I note that you've omitted registers as a possible choice for storage. Lots of variables are enregistered, so they go on neither the stack nor the heap.

The better way to think of it is that there is short term storage and long term storage.

Is there any quick and straightforward way to demonstrate that a variable is stored on stack or on heap?

Attempt to compute the lifetime of the variable. If you can do so easily, and the lifetime is less than or equal to the duration of the method activation which created it, then it is likely on the short term pool. If not, it's likely on the long-term pool.

In C++, I can get a variable's memory address and view its value stored in stack or heap memory by VS memory window.

Doing so with the & operator can change where the variable is stored! If you take the address of a variable then it cannot be enregistered because registers don't have addresses. A technique which changes what it attempts to describe is an unreliable technique.

Also, you are perhaps forgetting that in C++ the stack and the heap are not the only possible storage locations.

For example, if I tell someone the reference type variables are stored on heap or the local value type variable on stack(right?). How can I show that explicitly?

Since those statements are false you cannot show them at all. It is simply false that references always go on the heap and that local variables of value type go on the stack. Example:

void M()
{
    string s = "";
    ...

The empty string is on the long term storage pool, but the empty string isn't stored in s in the first place. A reference to the empty string is stored in s. That reference can be put in the short term pool.

Remember, the actual referants of a reference type do not go in variables at all. Variables of reference type hold references -- that's why they're called reference types.

Now, a field of a reference type is a variable, and that variable does not have a known lifetime, so that variable must go on the long term storage pool:

class C { public int x; }
...
C M() { C c = new C(); return c; }

x is a variable of value type but because it is a field belonging to a reference type, it must be on the long-term pool. c is a variable of reference type so it holds a reference; the lifetime of the variable c is short, so c goes on the short-term pool. Again do not confuse the reference with the thing being referred to.

Example:

Action<int> M()
{
    int x = 123;
    return y => { x = y; Console.WriteLine(x); };
}

Local variable x is of value type but you cannot compute its lifetime and therefore it must be on the long term storage pool.

Since your statement that variables of reference type go on the heap and local variables of value type go on the stack is false, there is no way to demonstrate its truth.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Thank you very much. Great pleasure to get the detailed explanation. – Wason Aug 04 '14 at 11:38
  • What the reference actually is when you say a reference is stored in one variable on stack? An address? Or a data struct containing a pointer to the referent? – Wason Aug 04 '14 at 12:54
  • @anaconda_wly: In *practice* a reference is implemented as an address to a location controlled by the garbage collector. But since there is no way for you to sensibly *use* that fact in a C# program, it is best to simply accept that a reference is something that implements reference semantics, and how it does so behind the scenes is not your concern. – Eric Lippert Aug 18 '14 at 18:17
  • Thanks for the detailed explanation! However, I think that the original question is not fully answered. How can one tell where a variable is allocated from the execution result of a program (instead of deducing it from the source code)? Or are you suggesting that it is simply impossible because any attempt to inspect the location of a variable will affect how it is allocated? – YAC Jan 04 '22 at 10:56
  • 1
    @YAC: That's correct; if the *program* attempts to determine the address of a variable then *the compiler is restricted to only allocating storage that has an address*. If the program does not attempt to determine the address of a variable then the compiler is free to enregister the variable or, for that matter, elide it if the variable is shown to never be read. If you want to know where your variable storage is in a given execution of a program, use a debugger. – Eric Lippert Jan 10 '22 at 23:31
  • 2
    @YAC: However, that doesn't reliably work either, since *the jitter knows whether the debugger is running when it jits the method* and might make different choices. What you really need to do is run your program and then *after* the variable is created, *attach the debugger and inspect it*. – Eric Lippert Jan 10 '22 at 23:32