1

As I understand, using structure value types will always give better performance than using reference types in an array or list. Is there any downside involved in using struct instead of class type in a generic list?

PS : I am aware that MSDN recommends that struct should be maximum 16 bytes, but I have been using 100+ byte structure without problems so far. Also, when I get the maximum stack memory error exceeded for using a struct, I also run out of heap space if I use a class instead.

paseena
  • 4,207
  • 6
  • 32
  • 51
  • Can you post where you read this at? I'd like to communicate to the source that this is simply wrong. – JaredPar Apr 11 '11 at 18:17

6 Answers6

4

There is a lot of misinformation out there about struct vs. reference types in .Net. Anything which makes blanket statements like "structs will always perform better in ..." is almost certainly wrong. It's almost impossible to make blanket statements about performance.

Here are several items related to value types in a generic collection which will / can affect performance.

  • Using a value types in a generic instantiation can cause extra copies of methods to be JIT'd at runtime. For reference types only one instance will be generated
  • Using value types will affect the size of the allocated array to be count * size of the specific value type vs. reference types which have all have the same size
  • Adding / accessing values in the collection will incur copy overhead. The performance of this changes based on the size of the item. For references again it's the same no matter the type and for value types it will vary based on the size
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    In other words: _in general_ (as much as it is possible to generalize), as value types get larger their list/array performance gets slower. And this doesn't even begin to address the problems that can arise if the types are mutable. – Joel Coehoorn Apr 11 '11 at 18:20
  • thanks for your reply. if an array is copied to another, i understand that there will be extra copies of valuetype. does it apply to a single use array too, i am not able to understand how extra copy of memory will be in valuetype and not in ref type. reference type will also be created, no? – paseena Apr 11 '11 at 18:27
2

As others have pointed out, there are many downsides to using large structures in a list. Some ramifications of what others have said:

Say you're sorting a list whose members are 100+ byte structures. Every time items have to be swapped, the following occurs:

var temp = list[i];
list[i] = list[j];
list[j] = temp;

The amount of data copied is 3*sizeof(your_struct). If you're sorting a list that's made up of reference types, the amount of data copied is 3*sizeof(IntPtr): 12 bytes in the 32-bit runtime, or 24 bytes in the 64-bit runtime. I can tell you from experience that copying large structures is far more expensive than the indirection inherent in using reference types.

Using structures also reduces the maximum number of items you can have in a list. In .NET, the maximum size of any single data structure is 2 gigabytes (minus a little bit). A list of structures has a maximum capacity of 2^31/sizeof(your_struct). So if your structure is 100 bytes in size, you can have at most about 21.5 million of them in a list. But if you use reference types, your maximum is about 536 million in the 32-bit runtime (although you'll run out of memory before you reach that limit), or 268 million in the 64-bit runtime. And, yes, some of us really do work with that many things in memory.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
1

using structure value types will always give better performance than using reference types in an array or list

There is nothing true in that statement.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
1

Take a look at this question and answer.

Community
  • 1
  • 1
BrandonZeider
  • 8,014
  • 2
  • 23
  • 20
1

With structs, you cannot have code reuse in the form of class inheritance. A struct can only implement interfaces but cannot inherit from a class or another struct whereas a class can inherit from another class and of course implement interfaces.

Bala R
  • 107,317
  • 23
  • 199
  • 210
0

When storing data in a List<T> or other collection (as opposed to keeping a list of controls or other active objects) and one wishes to allow the data to change, one should generally follow one of four patterns:

  1. Store immutable objects in the list, and allow the list itself to change
  2. Store mutable objects in the list, but only allow objects created by the owner of the list to be stored therein. Allow outsiders to access the mutable objects themselves.
  3. Only store mutable objects to which no outside references exist, and don't expose to the outside world any references to objects within the list; if information from the list is requested, copy it from the objects in the list.
  4. Store value types in the list.

Approach #1 is the simplest, if the objects one wants to store are immutable. Of course, the requirement that objects be immutable can be somewhat limiting.

Approach #2 can be convenient in some cases, and it permits convenient updating of data in the list (e.g. MyList[index].SomeProperty += 5;) but the exact semantics of how returned properties are, or remain, attached to items in the list may sometimes be unclear. Further, there's no clear way to load all the properties of an item in the list from an 'example' object.

Approach #3 has simple-to-understand semantics (changing an object after giving it to the list will have no effect, objects retrieved from the list will not be affected by subsequent changes to the list, and changes to objects retrieved from a list will not affect the list themselves unless the objects are explicitly written back), but requires defensive copying on every list access, which can be rather bothersome.

Approach #4 offers essentially the same semantics as approach #3, but copying a struct is cheaper than making a defensive copy of a class object. Note that if the struct is mutable, the semantics of:

  var temp = MyList[index];
  temp.SomeField += 5;
  MyList[index] temp;

are clearer than anything that can be achieved with so-called "immutable" (i.e. mutation-only-by-assignment) structs. To know what the above does, all one needs to know about the struct is that SomeField is a public field of some particular type. By contrast, even something like:

  var temp = MyList[index];
  temp = temp.WithSomeField(temp.SomeField + 5);
  MyList[index] temp;

which is about the best one could hope for with such a struct, would be much harder to read than the easily-mutable-struct version. Further, to be sure of what the above actually does, one would have to examine the definition of the struct's WithSomeField method and any constructors or methods employed thereby, as well as all of the struct's fields, to determine whether it had any side-effects other than modifying SomeField.

supercat
  • 77,689
  • 9
  • 166
  • 211