"Reference types (classes, interfaces, delegates) are always allocated on the heap and never on the stack."
Yes, reference types are generally allocated on the heap but there's no guarantee and clever compilers can and will allocate objects on the stack if they can prove that the reference to the object never escapes (you can read up on Escape analysis).
"Keywords such as ref and out, ref return and ref local (C#7.0), in (C#7.2) allow accessing value types by reference. This means that instead of copying the value, the consuming code will receive a reference to the value instead, be it on a stack or on a heap, as long as the lifetime of that value type is longer than that of consuming code"
Yeah, that's what you'd intuitively think, but sadly that's (generally) not the case. Value types are specified to be immutable, which the compilers has to guarantee. That means if you pass a value type around via ref or similar you'll get a defensive copy. Same thing if you try to call methods on a struct.
This has caused quite the performance problems over the years. Luckily readonly struct was introduced to avoid this problem.
It would also be a good idea to mention that what you're describing about the GC and LOH in particular is an implementation detail and not contractually guaranteed.
Also finalization strategies are also implementation defined. Currently it is not true that the GC stops everything while finalizers are being run (after all we have a dedicated thread for it), which is one reason that makes finalizers so complicated to implement correctly. There is also no guarantee that finalizers won't run on the thread pool instead of a single dedicated thread in the future (so don't rely on finalizers being sequentially executed!). Actually I'm not even sure if .Net Core still has a dedicated thread here.
In all fairness, everything about how the memory management works in CLR is an implementation detail, although it doesn't stop interviewers from asking these questions. :)
Value types are specified to be immutable, which the compilers has to guarantee.
You're thinking about ref readonly and in specifically, in which case yes, a defensive copy has to be made because the compiler cannot be sure that the object is not mutated.
"In all fairness, everything about how the memory management works in CLR is an implementation detail, although it doesn't stop interviewers from asking these questions. :)"
I know people who ask these questions in the hope of getting push back, but I'll agree - lots of questionable interview questions out there :)
Also yes you're right, the copy only happens if you use in or access a property of a readonly field that's a struct.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
"Reference types (classes, interfaces, delegates) are always allocated on the heap and never on the stack."
Yes, reference types are generally allocated on the heap but there's no guarantee and clever compilers can and will allocate objects on the stack if they can prove that the reference to the object never escapes (you can read up on Escape analysis).
"Keywords such as ref and out, ref return and ref local (C#7.0), in (C#7.2) allow accessing value types by reference. This means that instead of copying the value, the consuming code will receive a reference to the value instead, be it on a stack or on a heap, as long as the lifetime of that value type is longer than that of consuming code"
Yeah, that's what you'd intuitively think, but sadly that's (generally) not the case. Value types are specified to be immutable, which the compilers has to guarantee. That means if you pass a value type around via
ref
or similar you'll get a defensive copy. Same thing if you try to call methods on a struct.This has caused quite the performance problems over the years. Luckily
readonly struct
was introduced to avoid this problem.It would also be a good idea to mention that what you're describing about the GC and LOH in particular is an implementation detail and not contractually guaranteed.
Also finalization strategies are also implementation defined. Currently it is not true that the GC stops everything while finalizers are being run (after all we have a dedicated thread for it), which is one reason that makes finalizers so complicated to implement correctly. There is also no guarantee that finalizers won't run on the thread pool instead of a single dedicated thread in the future (so don't rely on finalizers being sequentially executed!). Actually I'm not even sure if .Net Core still has a dedicated thread here.
In all fairness, everything about how the memory management works in CLR is an implementation detail, although it doesn't stop interviewers from asking these questions. :)
You're thinking about
ref readonly
andin
specifically, in which case yes, a defensive copy has to be made because the compiler cannot be sure that the object is not mutated."In all fairness, everything about how the memory management works in CLR is an implementation detail, although it doesn't stop interviewers from asking these questions. :)"
I know people who ask these questions in the hope of getting push back, but I'll agree - lots of questionable interview questions out there :)
Also yes you're right, the copy only happens if you use
in
or access a property of a readonly field that's a struct.