As you saw in Chapter 2, all Visual C# objects are derived from the object type. Unlike some other object-oriented languages, in C# even the primitive types such as integers and floating-point variables are derived from object. Visual C# isn’t the first language to unify the type system—Smalltalk is an early example of a language in which all objects are derived from a single base class and are allocated from a single heap. This unified type system provides for consistent interaction with all objects, albeit at a performance cost—allocating every object in a system dynamically (including integers and similar primitive types) places a significant load on the runtime. The challenge for the developers of the .NET platform and Visual C# was to develop a type system unified around a common base class that would be efficient enough for general-purpose programming.
In C or C++, the programmer can decide on a case-by-case basis whether an object should be allocated on the heap or the stack. A heap-allocated object costs slightly more to allocate but offers benefits: a heap-allocated object is easily shared with other classes and can have a lifetime that exceeds the life of the current method. On the other hand, the heap-allocated object’s lifetime must be explicitly managed—a mistake will lead to memory leaks or program failure.
In contrast, a stack-allocated object is more efficient in terms of performance and memory allocation but isn’t easily shared with other methods, as its lifetime is strictly bound by the method that declares it. When the enclosing method returns, the object is automatically destroyed. Remember, the stack is an area of memory that’s allocated when a method or statement block is entered and freed when the method or statement block is exited.
The approach taken for .NET languages was to optimize the runtime for types with short lifetimes that are frequently used. These types are allocated with the same scope as their surroundings. A value type declared as a field in an enclosing reference type is allocated “in-line” for objects of the reference type. A value type declared in a method call is always allocated on the temporary execution stack rather than on the managed heap, offering performance gains for these temporary objects. The term value types indicates that objects of these types are always used directly by value, without references. Types allocated on the managed heap are known as reference types, to emphasize that objects of these types are always indirectly referenced. In this chapter, we’ll look at these two type categories and how to use them and at how Visual C# and the common language runtime allocate, treat, and destroy them.