Introduction to the Common Language Runtime (CLR)
What is the Common Language Runtime (CLR)?
What is the CLR?
The Common Language Runtime (CLR) is a complete, high level virtual machine designed to support a broad variety of programming languages and interoperation among them.
All interesting programs need some runtime library that allows them to interact with the other resources of the machine (such as user input, disk files, network communications, etc).
The program also needs to be converted in some way (either by interpretation or compilation) to a form that the native hardware can execute directly.
What is the CLR?
The CLR fixes problems like these by defining a very complete specification.
Thus, among other things, the CLR specifies:
- A GC-aware virtual machine with its own instruction set
- A rich meta data representation for program declarations
- A file format that specifies exactly how to lay the bits down in a file
- The lifetime semantics of a loaded program, the mechanism by which one CLR EXE file can refer to another CLR EXE
- A class library that leverages the features that the CLR provides (e.g., garbage collection, exceptions, or generic types)
What is the CLR?
Multi-language Support
In short, the runtime is a complete specification of the exact bits one has to put in a file to create and run a program.
The virtual machine that runs these files is at a high level appropriate for implementing a broad class of programming languages.
This virtual machine, along with an ever growing body of class libraries that run on that virtual machine, is what we call the common language runtime (CLR).
The Primary Goal of the CLR
The Primary Goal of the CLR
The goal of the CLR is to make programming easy.
Some important but often overlooked ease of use features include:
- Simplified languages
- A dedication to simplicity in the class library
- Strong consistency in the naming in the class library
- Great support in the tool chain needed to create an application
Fundamental Features of the CLR
Fundamental Features of CLR
The runtime has many features, so it is useful to categorize them as follows:
- Fundamental features:
- Garbage Collection
- Memory Safety and Type Safety
- High level support for programming languages.
- Secondary features:
- Program isolation with AppDomains
- Program Security and sandboxing
- Other Features
- Versioning
- Debugging/Profiling
Fundamental Features of CLR
The CLR Garbage Collector (GC)
Garbage collection is a wonderful user feature because it simplifies programming. The most obvious simplification is that most explicit delete operations are no longer necessary.
While removing the delete operations is important, the real value to the programmer is a bit more subtle:
- Garbage collection simplifies interface design because you no longer have to carefully specify which side of the interface is responsible for deleting objects passed across the interface.
- Garbage collection eliminates a whole class of common user mistakes.
Fundamental Features of CLR
The CLR Garbage Collector (GC)
- Garbage collection requires ALL references to the GC heap to be tracked.
- The CLR supports multiple concurrent threads of execution with a single process.
CLR needs to track all references to the GC heap almost all the time.
Fundamental Features of CLR
The Concept of "Managed Code"
Code that does the extra bookkeeping so that it can report all of its live GC references "almost all the time" is called managed code (because it is "managed" by the CLR).
Code that does not do this is called unmanaged code.
Thus all code that existed before the CLR is unmanaged code, and in particular, all operating system code is unmanaged.
Fundamental Features of CLR
Memory and Type Safety
A GC is necessary to provide memory safety guarantees.
Effectively, the only way you have to determine if a delete is correct is to check it at runtime.
This is exactly what a GC does (checks to see if memory is still live).
Thus, for any programs that need heap-style memory allocations, if you want to guarantee memory safety, you need a GC.
Fundamental Features of CLR
Verifiable Code -
Enforcing Memory and Type Safety
In practice, the number of run-time checks needed is actually very small:
- Casting a pointer to a base type to be a pointer to a derived type (the opposite direction can be checked statically)
- Array bounds checks (just as we saw for memory safety)
- Assigning an element in an array of pointers to a new (pointer) value. This particular check is only required because CLR arrays have liberal casting rules.
High Level Features
High Level Features
Object Oriented Programming
- Inheritance
- Polymorphism
- Encapsulation
High Level Features
Object Oriented Programming
Run-time dispatch logic could have been implemented using primitive CIL instructions without direct support in the runtime, it would have suffered from two important disadvantages:
- It would not be type safe (mistakes in the dispatch table are catastrophic errors)
- Each object-oriented language would likely implement a slightly different way of implementing its virtual dispatch logic. As result, interoperability among languages would suffer (one language could not inherit from a base type implemented in another language).
High Level Features
Object Oriented Programming
It is important to keep in mind that while the runtime supports these object-oriented concepts, it does not require their use. Languages without the concept of inheritance (e.g., functional languages) simply don't use these facilities.
High Level Features
Value Types (and Boxing)
The key characteristics of value types are:
- Each local variable, field, or array element of a value type has a distinct copy of the data in the value.
- When one variable, field or array element is assigned to another, the value is copied.
- Equality is always defined only in terms of the data in the variable (not its location).
- Each value type also has a corresponding reference type which has only one implicit, unnamed field. This is called its boxed value. Boxed value types can participate in inheritance and have object identity (although using the object identity of a boxed value type is strongly discouraged).
High Level Features
Exceptions
Exceptions are a language feature that allow programmers to throw an arbitrary object at the point that a failure occurs.
When an object is thrown, the runtime searches the call stack for a method that declares that it can catch the exception.
If such a catch declaration is found, execution continues from that point.
High Level Features
Parameterized Types (Generics)
The main reason is that parameterized types make programming easier.
The reason for this is subtle. The easiest way to see the effect is to imagine what a class library would look like if all types were replaced with a generic Object type.
This effect is not unlike what happens in dynamically typed languages like JavaScript.
In such a world, there are simply far more ways for a programmer to make incorrect (but type-safe) programs.
High Level Features
Programs as Data (Reflection APIs)
System.Reflection interface allows you to explore almost all aspects of a program (what types it has, the inheritance relationship, and what methods and fields are present).
In addition to simply inspecting programs at run time, it is also possible to perform operations on them (e.g., invoke methods, set fields, etc.).
In fact, the runtime libraries use this capability to generate code for "serializing" objects to store in a file or send across the network.
Other Features
of the CLR
Other Features
of the CLR
Interoperation with Unmanaged Code
There are two main "flavors" of interoperation:
- ability simply to call unmanaged functions (Platform Invoke or PINVOKE)
- interoperating with COM code
Other Features
of the CLR
Ahead of time Compilation
Сode that is generated from the CIL can be saved in a file using a tool called crossgen (similar to .NET Framework NGEN tool).
This avoids large amounts of compilation time at run time and is very important because the class library is so large.
Other Features
of the CLR
Threading
CLR is responsible for creating the necessary threads to do the work.
- System.Threading.Thread - 1-to-1 wrapper over the operating system notion of a thread of execution.
- ThreadPool - responsible for ensuring that the optimal number of threads are used to dispatch the work.
- Task Parallel Library
Summary and Resources
Summary and Resources
Phew! The runtime does a lot! It has taken many pages just to describe some of the features of the runtime, without even starting to talk about internal details. The hope is, however, that this introduction will provide a useful framework for a deeper understanding of those internal details. The basic outline of this framework is:
- The Runtime is a complete framework for supporting programming languages
- The Runtime's goal is to make programming easy.
- The Fundamental features of the runtime are:
- Garbage Collection
- Memory and Type Safety
- Support for High-Level Language Features
Summary and Resources
Introduction to the Common Language Runtime (CLR)
By Pavel Nasovich
Introduction to the Common Language Runtime (CLR)
At the heart of the .NET Framework is an execution engine called the Common Language Runtime. Designed from the ground up to support a myriad of programming language styles, the CLR provides a common type system, automatic memory management, support for concurrent execution and etc.
- 1,353