Is struct tearing an issue for Memory<T>? - c#

First things first:
I know what Span<T> and Memory<T> are
I know why Span<T> must reside on the Stack only
I (conceptionally) know what struct tearing is
What remains unclear to me:
Isn't struct tearing also an issue for Memory<T>? As far as I understood, basically every type bigger than WORD-size can/will be affected by that. Even further, when such a type can be used in a multithreaded reader-writer-scenario it could lead to race conditions as described in the link below.
To get to the point: Wouldn't this example also rise the issue of an potentially inconsistent Memory<T> object when used instead of Span<T>:
internal class Buffer {
Memory<byte> _memory = new byte[1024];
public void Resize(int newSize) {
_memory = new byte[newSize]; // Will this update atomically?
}
public byte this[int index] => _memory.Span[index]; // Won't this also possibly see partial update?
}
According to the implementation of CoreFX Memory<T> also sequentially lays out a (managed object) reference, its length and an index. Where's the difference to Span<T> I'm missing, that makes Memory<T> suitable for those scenarios?

From reading the comments in Memory<T>, it looks like it can absolutely be torn.
However, there seem to be two places where this actually matters: Memory<T>.Pin() and Memory<T>.Span.
The important thing to note is that (as far as I can work out) we don't care about tearing in a way which means we still point to somewhere in the object we refer to -- although our caller might get some strange data that it wasn't expecting, that's safe in the sense that they won't get an AccessViolationException. They will just have a race condition which produces unexpected results, as a consequence of having unsynchronized threaded access to a field.
Memory<T>.Span gets a Span<T> from the Memory<T>. It has this comment:
If the Memory or ReadOnlyMemory instance is torn, this property getter has undefined behavior. We try to detect this condition and throw an exception, but it's possible that a torn struct might appear to us to be valid, and we'll return an undesired span. Such a span is always guaranteed at least to be in-bounds when compared with the original Memory instance, so using the span won't AV the process.
So, we can absolutely have a torn Memory<T>, and then try to create a Span<T> from it. In this case, there's a check in the code which throws an exception if the Memory<T> has torn in such a way that it now refers to some memory outside of the object referred to by the Memory<T>.
If it has torn in a way that it still refers to somewhere in the original object, then that's OK - our caller might not be reading the thing it was expecting to read, but at least they won't get an AccessViolationException, which is what we're trying to avoid.
Note that Span<T> is unable to implement this same check (even if it wanted to). Memory<T> keeps references to the object, the start offset, and the length. Span<T> only keeps references to some memory address inside the object and the length.
Memory<T>.Pin() is an unsafe method, which has this comment:
It's possible that the below logic could result in an AV if the struct is torn. This is ok since the caller is expecting to use raw pointers, we're not required to keep this as safe as the other Span-based APIs.
Again, we can tear in a way that we no longer refer to somewhere inside the object we refer to. However this method is unsafe, and we don't care.

Related

Is returning a Span<byte> from a temporary byte[] dangerous (will generate an exception possibly on usage)?

In a .NET Core 3.0 project, I have an interface that return a Span<byte>. This works for a large set of classes except one particular implementation which can generate its data on the fly (due to not caching it).
The implementation looks like:
public Span<byte> Data => CompileBytes();
where it would be something like (this is abstract code but pretty close to a use case)
public byte[] CompileBytes()
{
using (MemoryStream stream = new MemoryStream())
{
foreach (IDataSource data in DataSources)
stream.Write(data.ByteArray);
return stream.ToArray();
}
}
I have been looking around online to see if there's a guarantee that this is safe to do but haven't found any.
My worry is that Span is a very thin layer around the data that the GC will ignore such that the GC assumes we will not let the span outlive the underlying buffer, and the temporary byte array that is created will eventually get GC'd, which means I could potentially have a ticking time bomb on my hands if it for some reason does a GC while someone other code is using the span. Is this the case? Can I return a Span<> for a temporary object and be perfectly okay (under the assumption it is properly used by staying in the bounds of the span)?
The definition seems to be implementation dependent so I can't figure out with my limited knowledge if it holds onto the reference or not... because if so, then I am safe and my question is answered.
The MSDN says 'memory safe' but I am unsure the exact specifics by which they define memory safe and if it covers my definition. As such, if it does, then this question is answered.
I am not using any unsafe code.
Having a reference to a managed array in a Span<T> is safe, even if it is the only reference to it.
As described in the article All About Span: Exploring a New .NET Mainstay, Span<T> uses a special way of storing these references, a ByReference<T>, which is implemented as a JIT intrinsic.
Quoting the linked article (section How Is Span<T> Implemented?):
Span<T> is actually written to use a special internal type in the runtime that’s treated as a just-in-time (JIT) intrinsic, with the JIT generating for it the equivalent of a ref T field
And section What Is Memory<T> and Why Do You Need It?
Span<T> is a ref-like type as it contains a ref field, and ref fields can refer not only to the beginning of objects like arrays, but also to the middle of them [...] These references are called interior pointers, and tracking them is a relatively expensive operation for the .NET runtime’s garbage collector.
The last part of that quote clarifies that the reference stored in Span<T> is indeed tracked by the GC, so it will not clean up memory that is still being referenced

How C# returns Structs

Structs are value types and thus are fully copied every time there is a manipulation on the struct. Since they are value types, structs are allocated in the stack and not in the heap.
I can see how structs can degrade the performance of methods when structs are passed as parameters, since they will be always copied in the stack, specially if they are big with lots of inner fields.
But I am curious about how C# deals with the return of structs.
In C the return is made by registers, or by reference using the heap if the value to be returned is too big for the registers. And practically all C# struct tutorials say structs lives in the stack, never in the heap.
So in the following code:
MyStruct ms = GetMyValue();
Where GetMyValue() is
MyStruct GetMyValue();
How will C# deal with the return of the struct for the ms variable? Specially if it's is too big for the registers? Will it in fact copy it to the heap and then copy it back again to the caller of the method and assign it to ms?
EDIT:
To address the comments left in the post:
I have read a few tutorial on C# structs before posting this, this tutorial in particular uses the word stack more times than I bother to count. And this MSDN tutorial also speaks about the stack, although it's from 2003, I don't think structs changed since then.
I am aware this might not be realted at all with C# but in fact be a matter of the JIT compiler it self or the CLR or something else I am not aware of. That's the purpose of my question, to learn more about the inner workings of C#, even if this is not actually related to the language itself.
There are C function call conventions, the best support for my Post is this StackOverflow post. When I first posted it in here I just said what I remembered, but since the SO answer says:
As for your specific question, it depends the ABI. Sometimes if the return value is larger than 4 bytes but not larger than 8 bytes, it can be split into EAX and EDX. But most of the time the calling function will just allocate some memory (usually on the stack) and pass a pointer to this area to the called function.
I might be wrong on this one, and I say might, because the answer says usually.
The true reason why I want to understand how structs are handled is because I have a project where I have to read a Serial Port multiple times to poll for data, this data will be returned by a method.
Since the data is just some bytes I thought I could get some performance out of structs instead of using a class to abstract the bytes incoming by the Serial Port, but if the return would pass the struct as a heap allocation my expectations on performance increase could be false.
Yes, I can make a simple test and compare performance, I know, but I wanted to actually learn how it's done behind the curtains, and not only memorize the outcome of my simulation. I like to know how the things that I work with actually work, and not only learn how to use them.
Value types are not only located on a stack. They also live in fields and in arrays. The key distinction to reference types is that value types are copied by value and have no identity. The stack vs. heap idea is false.
In C the return is made by registers, or by reference using the heap if the value to be returned is too big for the registers
The heap is not involved. The caller allocates spaces for the return value to be placed in. It passes a pointer to that space. The callee can fill that space. The .NET CLR does this as well. Of course this is an implementation detail.
but I wanted to actually learn
This is very good. You could not have tested what I just told you. You need to be a little more critical in what you believe what others say. Either you had bad tutorials or you read them in an imprecise way.
I can see how structs can degrade the performance of methods when structs are passed as parameters, since they will be always copied in the stack
This is not always the case I think. I'm not quite sure but I think the JIT can sometimes pass structs in registers. The .NET JITs really do not optimize much but I think this is an optimization that works to a certain degree. Probably driven by the existence of some one-field structs such as DateTime.
structs do not always live on the stack. if you allocate a struct inside of a function, it lives its life on the stack. if it's a field of a reference type(class/array(implicitly derived from System.Array/Object), it lives its life on the heap. as far as how theyre returned, that might be up to the ABI for that CPU architecture.
from the sounds of it, you've never dealt with IL/assembly/code generation, so lets build a dynamic method thats equivalent to MyStruct ms = GetMyValue()/what the compiler would generate in context of the word stack. "things" are never actually returned. thing(s, in a tuple sense i'm sure), are pushed onto the stack, and then a return instruction is emitted. leaving the return value(s) for the caller. we're going to assume GetMyValue() allocates a new MyStruct and assigns it to a local variable. the generated code would look something like this(i extend the ILGenerator class):
ILGenerator generator = dynamicMethod.GetILGenerator();
generator
.DeclareLocal(typeof(MyStruct))
.EmitCall(OpCodes.Call, typeof(EncapsulatingClass).GetMethod("GetMyValue"))
.Emit(OpCodes.Stloc, 0);
what happens here is(some of this is my assumption on how the CLI runtime works):
the calling function reserves a slot of typeof(MyStruct) at the current local list index.
GetMyValue() is called, reserves a MyStruct local the same way the method we are building does, emits an OpCodes.Newobj, which allocates and adjusts ESP(extended stack pointer) downward in the amount of sizeof(MyStruct), emits OpCodes.Stloc to store ESP minus sizeof(MyStruct) into the reserved local index, does some stuff with its fields, calls Emit(OpCodes.Ldloc, 0) to push the address the local points to onto the evaluation stack for the calling function, and emits an OpCodes.Ret to return.
the calling function emits an OpCodes.Stloc to store(copy) the contents of the MyStruct the top of the evaluation stack points to(how this happens, well i'm sure the answer is it depends, unfortunately), at local index 0.
i'm not an expert on how the CLI runtime is constructed by any means, so a lot of this is an assumption of what happens. take it with a grain of salt, and i'm by no means a CPU engineering expert. how the instruction stream segment of OpCodes.Ldloc, OpCodes.Ret, OpCodes.Stloc -- ms = GetMyValue() -- is treated, is probably up to how the JITer translates the IL into actual cpu specific machine instructions. such as X86. what determines if a struct will be returned into a register, is probably limited to one register only, so whatever the biggest register is, and if whatever struct will fit inside of it. i know CPU's can combine registers for memory offsets, but i'm not sure if that applies to returning structs inside of multiple registers. another thing to keep in mind, GetMyValue() went out of scope, which means the struct GetMyValue() allocated, in a scope sense, doesn't exist anymore, but in a stack sense(where it was allocated), it does, so the JITer could very well have just taken the address OpCodes.Ldloc pushed onto the stack, and placed it directly into the callers local index 0. since nothing can possibly copy it anymore due to the function returning. making the caller the new owner of the struct. avoiding any copying and registers altogether in this special case. this might be where calling conventions come into play as well. the problem is, if you allocated three structs in GetMyValue() for whatever reason, returning any struct after the first struct allocated would break that optimization, which is where the next optimization, return the struct inside a register(if it fits), comes into play. leaving the worst case scenario, copying its contents purely onto the stack again for the caller. i could be wrong, and anyone is more than welcome to chime in and correct me. a good place to start, would be github and see how the runtime handles OpCodes.Ldloc/Stloc for structs. i would imagine that's a good spot to look when it comes to getting the answers you need.
EDIT: any tutorial you've read that says structs are always allocated on the stack, have them all DDoS'd.

Should I use Class or Struct in the following case (data structure with many fields)? [duplicate]

I'm about to create 100,000 objects in code. They are small ones, only with 2 or 3 properties. I'll put them in a generic list and when they are, I'll loop them and check value a and maybe update value b.
Is it faster/better to create these objects as class or as struct?
EDIT
a. The properties are value types (except the string i think?)
b. They might (we're not sure yet) have a validate method
EDIT 2
I was wondering: are objects on the heap and the stack processed equally by the garbage collector, or does that work different?
Is it faster to create these objects as class or as struct?
You are the only person who can determine the answer to that question. Try it both ways, measure a meaningful, user-focused, relevant performance metric, and then you'll know whether the change has a meaningful effect on real users in relevant scenarios.
Structs consume less heap memory (because they are smaller and more easily compacted, not because they are "on the stack"). But they take longer to copy than a reference copy. I don't know what your performance metrics are for memory usage or speed; there's a tradeoff here and you're the person who knows what it is.
Is it better to create these objects as class or as struct?
Maybe class, maybe struct. As a rule of thumb:
If the object is :
1. Small
2. Logically an immutable value
3. There's a lot of them
Then I'd consider making it a struct. Otherwise I'd stick with a reference type.
If you need to mutate some field of a struct it is usually better to build a constructor that returns an entire new struct with the field set correctly. That's perhaps slightly slower (measure it!) but logically much easier to reason about.
Are objects on the heap and the stack processed equally by the garbage collector?
No, they are not the same because objects on the stack are the roots of the collection. The garbage collector does not need to ever ask "is this thing on the stack alive?" because the answer to that question is always "Yes, it's on the stack". (Now, you can't rely on that to keep an object alive because the stack is an implementation detail. The jitter is allowed to introduce optimizations that, say, enregister what would normally be a stack value, and then it's never on the stack so the GC doesn't know that it is still alive. An enregistered object can have its descendents collected aggressively, as soon as the register holding onto it is not going to be read again.)
But the garbage collector does have to treat objects on the stack as alive, the same way that it treats any object known to be alive as alive. The object on the stack can refer to heap-allocated objects that need to be kept alive, so the GC has to treat stack objects like living heap-allocated objects for the purposes of determining the live set. But obviously they are not treated as "live objects" for the purposes of compacting the heap, because they're not on the heap in the first place.
Is that clear?
Sometimes with struct you don't need to call the new() constructor, and directly assign the fields making it much faster that usual.
Example:
Value[] list = new Value[N];
for (int i = 0; i < N; i++)
{
list[i].id = i;
list[i].isValid = true;
}
is about 2 to 3 times faster than
Value[] list = new Value[N];
for (int i = 0; i < N; i++)
{
list[i] = new Value(i, true);
}
where Value is a struct with two fields (id and isValid).
struct Value
{
int id;
bool isValid;
public Value(int i, bool isValid)
{
this.i = i;
this.isValid = isValid;
}
}
On the other hand is the items needs to be moved or selected value types all that copying is going to slow you down. To get the exact answer I suspect you have to profile your code and test it out.
Arrays of structs are represented on the heap in a contiguous block of memory, whereas an array of objects is represented as a contiguous block of references with the actual objects themselves elsewhere on the heap, thus requiring memory for both the objects and for their array references.
In this case, as you are placing them in a List<> (and a List<> is backed onto an array) it would be more efficient, memory-wise to use structs.
(Beware though, that large arrays will find their way on the Large Object Heap where, if their lifetime is long, may have an adverse affect on your process's memory management. Remember, also, that memory is not the only consideration.)
Structs may seem similar to classes, but there are important differences that you should be aware of. First of all, classes are reference types and structs are value types. By using structs, you can create objects that behave like the built-in types and enjoy their benefits as well.
When you call the New operator on a class, it will be allocated on the heap. However, when you instantiate a struct, it gets created on the stack. This will yield performance gains. Also, you will not be dealing with references to an instance of a struct as you would with classes. You will be working directly with the struct instance. Because of this, when passing a struct to a method, it's passed by value instead of as a reference.
More here:
http://msdn.microsoft.com/en-us/library/aa288471(VS.71).aspx
If they have value semantics, then you should probably use a struct. If they have reference semantics, then you should probably use a class. There are exceptions, which mostly lean towards creating a class even when there are value semantics, but start from there.
As for your second edit, the GC only deals with the heap, but there is a lot more heap space than stack space, so putting things on the stack isn't always a win. Besides which, a list of struct-types and a list of class-types will be on the heap either way, so this is irrelevant in this case.
Edit:
I'm beginning to consider the term evil to be harmful. After all, making a class mutable is a bad idea if it's not actively needed, and I would not rule out ever using a mutable struct. It is a poor idea so often as to almost always be a bad idea though, but mostly it just doesn't coincide with value semantics so it just doesn't make sense to use a struct in the given case.
There can be reasonable exceptions with private nested structs, where all uses of that struct are hence restricted to a very limited scope. This doesn't apply here though.
Really, I think "it mutates so it's a bad stuct" is not much better than going on about the heap and the stack (which at least does have some performance impact, even if a frequently misrepresented one). "It mutates, so it quite likely doesn't make sense to consider it as having value semantics, so it's a bad struct" is only slightly different, but importantly so I think.
The best solution is to measure, measure again, then measure some more. There may be details of what you're doing that may make a simplified, easy answer like "use structs" or "use classes" difficult.
A struct is, at its heart, nothing more nor less than an aggregation of fields. In .NET it's possible for a structure to "pretend" to be an object, and for each structure type .NET implicitly defines a heap object type with the same fields and methods which--being a heap object--will behave like an object. A variable which holds a reference to such a heap object ("boxed" structure) will exhibit reference semantics, but one which holds a struct directly is simply an aggregation of variables.
I think much of the struct-versus-class confusion stems from the fact that structures have two very different usage cases, which should have very different design guidelines, but the MS guidelines don't distinguish between them. Sometimes there is a need for something which behaves like an object; in that case, the MS guidelines are pretty reasonable, though the "16 byte limit" should probably be more like 24-32. Sometimes, however, what's needed is an aggregation of variables. A struct used for that purpose should simply consist of a bunch of public fields, and possibly an Equals override, ToString override, and IEquatable(itsType).Equals implementation. Structures which are used as aggregations of fields are not objects, and shouldn't pretend to be. From the structure's point of view, the meaning of field should be nothing more or less than "the last thing written to this field". Any additional meaning should be determined by the client code.
For example, if a variable-aggregating struct has members Minimum and Maximum, the struct itself should make no promise that Minimum <= Maximum. Code which receives such a structure as a parameter should behave as though it were passed separate Minimum and Maximum values. A requirement that Minimum be no greater than Maximum should be regarded like a requirement that a Minimum parameter be no greater than a separately-passed Maximum one.
A useful pattern to consider sometimes is to have an ExposedHolder<T> class defined something like:
class ExposedHolder<T>
{
public T Value;
ExposedHolder() { }
ExposedHolder(T val) { Value = T; }
}
If one has a List<ExposedHolder<someStruct>>, where someStruct is a variable-aggregating struct, one may do things like myList[3].Value.someField += 7;, but giving myList[3].Value to other code will give it the contents of Value rather than giving it a means of altering it. By contrast, if one used a List<someStruct>, it would be necessary to use var temp=myList[3]; temp.someField += 7; myList[3] = temp;. If one used a mutable class type, exposing the contents of myList[3] to outside code would require copying all the fields to some other object. If one used an immutable class type, or an "object-style" struct, it would be necessary to construct a new instance which was like myList[3] except for someField which was different, and then store that new instance into the list.
One additional note: If you are storing a large number of similar things, it may be good to store them in possibly-nested arrays of structures, preferably trying to keep the size of each array between 1K and 64K or so. Arrays of structures are special, in that indexing one will yield a direct reference to a structure within, so one can say "a[12].x = 5;". Although one can define array-like objects, C# does not allow for them to share such syntax with arrays.
Use classes.
On a general note. Why not update value b as you create them?
From a c++ perspective I agree that it will be slower modifying a structs properties compared to a class. But I do think that they will be faster to read from due to the struct being allocated on the stack instead of the heap. Reading data from the heap requires more checks than from the stack.
Well, if you go with struct afterall, then get rid of string and use fixed size char or byte buffer.
That's re: performance.

Why structs cannot have destructors?

What is best answer on interview on such question you think?
I think I didn't find a copy of this here, if there is one please link it.
Another way of looking at this - rather than just quoting the spec which says that structs can't/don't have destructors - consider what would happen if the spec was changed so that they did - or rather, let's ask the question: can we guess why did the language designers decide to not allow structs to have 'destructors' in the first place?
(Don't get hung up on the word 'destructor' here; we're basically talking about a magic method on structs that gets called automatically when the variable goes out of scope. In other words, a language feature analogous to C++'s destructors.)
The first thing to realize is that we don't care about releasing memory. Whether the object is on the stack or on the heap (eg. a struct in a class), the memory will be taken care of one way or another sooner or later; either by being popped off the stack or by being collected. The real reason for having something that's destructor-like in the first place is for managing external resources - things like file handles, window handles, or other things that need special handling to get them cleaned up that the CLR itself doesn't know about.
Now supposed you allow a struct to have a destructor that can do this cleanup. Fine. Until you realize that when structs are passed as parameters, they get passed by value: they are copied. Now you've got two structs with the same internal fields, and they're both going to attempt to clean up the same object. One will happen first, and so code that is using the other one afterwards will start to fail mysteriously... and then its own cleanup will fail (hopefully! - worst case is it might succeed in cleaning up some other random resource - this can happen in situations where handle values are reused, for example.)
You could conceivably make a special case for structs that are parameters so that their 'destructors' don't run (but be careful - you now need to remember that when calling a function, it's always the outer one that 'owns' the actual resource - so now some structs are subtly different to others...) - but then you still have this problem with regular struct variables, where one can be assigned to another, making a copy.
You could perhaps work around this by adding a special mechanism to assignment operations that somehow allows the new struct to negotiate ownership of the underlying resource with its new copy - perhaps they share it or transfer ownership outright from the old to the new - but now you've essentially headed off into C++-land, where you need copy constructors, assignment operators, and have added a bunch of subtleties waiting to trap the unaware novice programmer. And keep in mind that the entire point of C# is to avoid that type of C++-style complexity as much as possible.
And, just to make things a bit more confusing, as one of the other answers pointed out, structs don't just exist as local objects. With locals, scope is nice and well defined; but structs can also be members of a class object. When should the 'destructor' get called in that case? Sure, you can do it when the container class is finalized; but now you have a mechanism that behaves very differently depending on where the struct lives: if the struct is a local, it gets triggered immediately at end of scope; if the struct is within a class, it gets triggered lazily... So if you really care about ensuring that some resource in one of your structs is cleaned up at a certain time, and if your struct could end up as a member of a class, you'd probably need something explicit like IDisposable/using() anyhow to ensure you've got your bases covered.
So while I can't claim to speak for the language designers, I can make a pretty good guess that one reason they decided not to include such a feature is because it would be a can of worms, and they wanted to keep C# reasonably simple.
From Jon Jagger:
"A struct cannot have a destructor. A destructor is just an override of object.Finalize in disguise, and structs, being value types, are not subject to garbage collection."
Every object other than arrays and strings is stored on the heap in the same way: a header which gives information about the "object-related" properties (its type, whether it's used by any active monitor locks, whether it has a non-suppressed Finalize method, etc.), and its data (meaning the contents of all the type's instance fields (public, private, and protected intermixed, with base-class fields appearing before derived-type fields). Because every heap object has a header, the system can take a reference to any object and know what it is, and what the garbage-collector is supposed to do with it. If the system has a list of all objects which have been created and have a Finalize method, it can examine every object in the list, see if its Finalize method is unsuppressed, and act on it appropriately.
Structs are stored without any header; a struct like Point with two integer fields is simply stored as two integers. While it is possible to have a ref to a struct (such a thing is created when a struct is passed as a ref parameter), the code that uses the ref has to know what type of struct the ref points to, since neither the ref nor the struct itself holds that information. Further, heap objects may only be created by the garbage-collector, which will guarantee that any object which is created will always exist until the next GC cycle. By contrast, user code can create and destroy structs by itself (often on the stack); if code creates a struct along with a ref to it, and passes that ref it to a called routine, there's no way that code can destroy the struct (or do anything at all, for that matter) until the called routine returns, so the struct is guaranteed to exist at least until the called routine exits. On the other hand, once the called routine exits, the ref it was given should be presumed invalid, since the caller would be free to destroy the struct at any time thereafter.
Becuase by definition destructors are used to destruct instances of classes, and structs are value types.
Ref: http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
By Microsoft's own words: "Destructors are used to destruct instances of classes." so it's a little silly to ask "Why can't you use a destructor on (something that is not a class)?" ^^

What happens when value types are created?

I'm developing a game using XNA and C# and was attempting to avoid calling new struct() type code each frame as I thought it would freak the GC out. "But wait," I said to myself, "struct is a value type. The GC shouldn't get called then, right?" Well, that's why I'm asking here.
I only have a very vague idea of what happens to value types. If I create a new struct within a function call, is the struct being created on the stack? Will it simply get pushed and popped and performance not take a hit? Further, would there be some memory limit or performance implications if, say, I need to create many instances in a single call?
Take, for instance, this code:
spriteBatch.Draw(tex, new Rectangle(x, y, width, height), Color.White);
Rectangle in this case is a struct. What happens when that new Rectangle is created? What are the implications of having to repeat that line many times (say, thousands of times)? Is this Rectangle created, a copy sent to the Draw method, and then discarded (meaning no memory getting eaten up the more Draw is called in that manner in the same function)?
P.S. I know this may be pre-mature optimization, but I'm mostly curious and wish to have a better understanding of what is happening.
When a new struct is created, it's contents are put straight into the location where you specify - if it's a method variable, it goes on the stack; if it's being assigned to a class variable, it goes inside the class instance being pointed to (on the heap).
When a struct variable is copied (or, in your case, passed to a function), the bytes making up the struct are all copied to the correct place on the stack or inside the class (if you're setting a field or property on an instance of a reference type).
Even though there may be copying of bytes, the JIT compiler will likely optimize all the unneccessary copies away so that it executes as fast as possible. Generally, it's not something you need to worry about - this is very much a micro-optimization :)
Does this answer your question?
While value types go on the stack, there's still performance implications to allocating and deallocating all that memory every frame -- especially on the Xbox 360. On a PC you'll likely not notice the difference, but on the 360 you probably will.
The value types are created on the stack if declared locally or on the heap if part of an object instance (as part of the object instance). In any case, struct instances are not collected by the GC, they are destroyed when their container goes out of scope.
The MSDN struct (C#) article has some more information about this.
This is just to add to thecoops answer. For reference types the new operator allocates a new instance of the type on the heap and calls the specified constructor.
For a struct, the new operator initializes the fields according to the specified constructor. It is however possible to instantiate a struct without using new. In that case all the fields in the struct are uninitialized and cannot be used until they have been explicitly initialized.
For more info see the description on MSDN.

Categories

Resources