Question

I know that boxing is a popular concept with plenty of information available on it, but I have a few questions which I can't really find answers to:

1) If boxing leads to a value type (struct) being converted to an object (Reference type), or reference type, then why use a value type which will be boxed and incur a performance penalty? I am aware of the benefits and suitability in certain cases of either a struct or class. It is said (1) that values (value types) tend to live on the stack in a temporary storage space, but how long for? If I don't need the type, how can I ensure it is taken care of and disposed at that moment? Or is this where the disposable pattern comes into play? I assume the reason to use a struct will be due to its benefits.

Interestingly, if I use a struct to store two strings and a DateTime field, the struct will hold two references (strings) and the DateTime together. I obviously assume this is quicker than the values being scattered. Is there anything I need to be aware of in this design? (2).

1) http://en.csharp-online.net/Classes, Structs, and Objects—Boxing and Unboxing

2) http://dotnetperls.com/Content/Struct-Examples.aspx

I have done a search on here for the answers I am after, but no luck. I usually do searches on this site for topics such as GC, generics, exception handling, etc, as there is a lot of wisdom to learn and share.

Thanks for the (potential) education to all posters! Please excuse any potential naivety. Learning the internals takes me nicely to spending some time on understanding IL, etc (something to tackle, soon).

Was it helpful?

Solution

If you never pass the value type into a reference variable then boxing will not occur. When you don't know then answer the following questions:

  • Act like primitive types.
  • Have an instance size under 16 bytes.
  • Are immutable.
  • Value semantics are desirable.

I also usually consider what is the lifetime of such a variable. If it is a local variable used within a method then I would tent to use struct (otherwise class).

OTHER TIPS

You should use value types because of their logical benefit, not the performance gains. That being said, because value types are managed on the stack, do not need to participate in garbage collection. If you have a type that is constantly created and discarded (like an int, float, double, etc), then you can get a good boost by turning these into structs. The thing to be careful of is that you should only really consider this if you can also make the struct immutable.

A couple other things to consider -

First, you want to make sure structs are immutable (in general). Because of this, it's a good rule of thumb to not have structs containing reference types. Strings can be an exception to this since they're immutable in C#, but in terms of a general-purpose rule of thumb for design, I'd be wary of this.

Second, there's another use case for structs that wasn't mentioned so far - large numbers of small objects. If you have a large list or array of small objects, structs provide dramatically better cache coherency, and are absolutely critical. This is why most 3D engines use structs for points/vectors - they tend to have large arrays of points for vertices, etc.

This is something worth paying attention to if performance is an important part of your application. For example, in one of my apps, changing a single type from a class to a struct shaved 40% off a long running (>5 minute runtime) process. Having the objects close together in memory if you are using them repeatedly in heavy math computations can provide huge gains.

Now - in your case, having 2 strings and a DateTime probably won't see any improvements from this. The type of routines that would work on strings are probably not doing heavy computation (hopefully), ie: transforming a half a million points in space, or doing a large matrix solution, etc.

Finally - you'll notice that .net3.5sp1 made structs much more useful. Prior to 3.5sp1 (on x86), there was no inlining of methods with struct calls. This limited the performance gains possible via structs. Updating your framework can make old struct code much, much faster (in certain cases).

You don't always need boxing, and with generics there is little need for that.
The memory used by value types (struct is a value type) will be claimed as
soon as the method ends/returns and you don't
need to do anything for that to happen.

Value types declared as instance members will be in memory until the object
is deleted by the GC.

Reference types are kept on the managed heap.
Reference types instantiated within a method will be deleted by the
garbage collector when no object is holding a reference to it.

GC works by itself and for the most part you should leave it alone.
You can not predict when an object is going to be deleted by the GC.

The Dispose pattern is used on reference types but will not force GC to delete
an object. It's usually used to free unmanaged resources.

For values in the stack consider the following:
Let's say you have a simple program with three methods, like below:
When this program is run, the Main method is run, and so on. Please follow the
numbers below:


Main
{
   // (0) Stack is empty
   int firstInt = 0;
   // (1) Stack now contains:
   //                     firstInt
   DoSomething1();
   // (7) Stack still contains:
   //                     firstInt
}
// Program ends

DoSomething()
{
   int anInteger = 0; 
   // (2) Stack now contains:
   //                    anInteger
   //                    firstInt
   DoMore()
   // (5) Stack now contains:
   //                     anInteger
   //                     firstInt
}
// (6) anInteger goes out of scope

DoMore
{
  int anotherInteger = 1; 
   // (3) Stack now contains:
   //                     anotherInteger
   //                     anInteger
   //                     firstInt
}
// (4) anotherInteger goes out of scope

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top