Are Structs "faster" than Classes - In general or in the .NET framework?

Viewed 7726

Since structs are value-types, their data is copied when passed into a method as an argument. Example:

int someInt = 7;

DoSomeMethod(someInt); // <-- This is passing the "value" 7.

So far, easy to understand, and you're probably wondering how my question is valid... so consider the following:

public struct TimmysStructOfGoodness
{
    public int SomeInt1;
    public int SomeInt2;
    public int SomeInt3;
    // ... later that day ...
    public int SomeInt999;
}

and then, with reference to the following code:

TimmysStructOfGoodness someStructOfGoodness = new blah blah blah...

DoSomeMethod(someStructOfGoodness); // <-- **HERE IS WHERE THE QUESTION APPLIES!**

Does the above statement try to allocate several megs of ram to "copy" my value-type (struct)?

If the answer is yes - then when/where is the line between "faster" and "slower"?

If no - then why not? Because what I know of value-types, this should be a problem.

MAJOR DISCLAIMER: I know that this has nothing to do with why you would use a struct verses a class, and I know that I will never make a struct with 999 fields - this is just a question of underlying internals and guts and the like :)

5 Answers

(updated, thanks to contributions from other users)

Unlike class, struct is created on stack. So, it is faster to instantiate (and destroy) a struct than a class.

Unless (as Adam Robinson pointed out) struct is a class member in which case it is allocated in heap, along with everything else.

On the other hand, every time you assign a structure or pass it to a function, it gets copied.

I don't think there's a hard limit for a struct size. Thousands of bytes is definitely too much. MSDN says:

Unless you need reference type semantics, a class that is smaller than 16 bytes may be more efficiently handled by the system as a struct.

This is - if you need to pass it by reference make it a class, regardless of the size.

On the second thought, you can still pass struct by reference simply by specifying ref in the function parameter list.

So, a large struct can actually be ok if you pass it by reference and use as a class member.

Structs and classes do not just have different performance, they behave differently too. You should use the one that is most suitable for the type you are implementing. Guidelines of when to use one or the other are clearly described on MSDN. Use a struct only if all the following apply:

  • It logically represents a single value, similar to primitive types (integer, double, and so on).
  • It has an instance size smaller than 16 bytes.
  • It is immutable.
  • It will not have to be boxed frequently.

If you are passing a struct to a function, you will get a copy of it. If your struct is large then it will result in copying a lot of data. A reference is typically implemented as 4 bytes (on x86) so passing an object requires only copying these 4 bytes.

Notice also that the above guidelines require that structs are small.

The performance implications of structs depend on exactly how you use such structs.

It's impossible to make a categorical statement about whether structs are faster or slower than reference types. It all depends on how you use them, and in what context.

Structs (value types in general) can end up allocated on either the stack or the heap - depending on their declaration context. If you declare it in the body of a method (and don't explicitly box it), the struct will end up on the stack. If you then pass that struct to a method that accepts it by value (as in you example), it will indeed be copied - but on the stack. Allocation on the stack is a very efficient process (BTW, the .NET heap is also very efficient) - but it is a copy process.

You can, of course, pass the struct using ref/out - in which case no copying will occur - a reference to the struct will be passed to the method. This may, or may not, be desirable - since it will allow the called method to change the contents of the struct.

A struct that is declared as a member of a class will actually be allocated on the heap (as part of the memory layout of the class). If you pass that class around, the struct will not be copied, but will still be accessible through the class reference.

You can also get a struct onto the heap by explicitly boxing it:

object x = new MyStruct( ... );  // boxed on the heap

Jon Skeet has a good article about where things end up in memory that you should read.

To add to the confusion, remember, if you don't need a copy passed to the other method, you can always pass the struct by reference to avoid making a copy ...

The answer to your question is: Yes. When you define a struct, each assignment incurs a copy operation.

There is not exact line which separates "fast" from "slow" because there are a lot of factors that affect speed WRT to structs, such as:

<correction> Structs are stored by value: on the stack or within the containing objects. Thus they promote cache locality as chances are higher that the relevant page is already loaded into CPU's cache where arbitrary heap pages are likely not to. </correction> Also, structs do not allow method overriding so method dispatch is also (marginally) faster.

On the other hand, each assignment incurs a copy. So if your code has a lot of assignments the advantages mentioned above will be outweighed by the cost of the copy operations. The break even point is different from one program to another (due to different characteristics of cache locality, method dispatching and assignments)

Related