What is the Difference Between Managed and Unmanaged Code?
When code runs in a common language runtime that has control over the execution of that code (e.g, in the Common Language Runtime[CLR] of .NET or the Java Runtime Environment [JRE]), then that code is considered to be managed. Code that runs out of these environments are unmanaged.
A managed code (such as the .Net framework) is one in which the application will only execute under the management of a Common Language Runtime (CLR) virtual machine which dictates how a managed code can be run. An unmanaged code (such as C++) does not have these limitations or frameworks it must fit within.
To explore this further, application source code is typically compiled from a particular language (e.g. C/C++, Swift, etc.) into a specific hardware platform’s native code via a compiler. This code is then parsed and processed directly in a hardware environment, which entails the binary code being processed by the Central Processing Unit (CPU), with the Operating System existing as the software environment link to the hardware. With specific software frameworks, such as the .Net framework and the Java Runtime Environment, code is instead compiled into an intermediate language (MSIL for .NET or byte code for Java). The MSIL/ byte code represents an intermediate executable that runs in the virtual machine (the CLR for the .NET and the JVM for Java). These virtual machines parse and convert the intermediate executable into native architectures executables. This way the original compiled code (intermediate code) never touches the CPU directly, but is executed within a software environment. The environment is the application virtual machine. This allows for greater interoperability and scalability in having the ability to parse and run code written in a variety of languages (for .NET) and run on different hardware environments. The original high level source code (e.g., Java, C#, VB#, etc.) ends up being compiled into code that is executed, run and managed by the CLR. This makes it a flexible, but powerful system of software management, as memory allocation, security, exception handling, garbage collection, etc. are all handled by the CLR. One of the significant benefits of running in the managed environment is that the runtime environment takes care of some issues that frequently trip up developers of unmanaged code. The runtime environment can help prevent buffer overflows, perform memory management, help perform exception management and more. Unmanaged code, on the other hand, must have all security processes, exception handling, memory allocation, etc. taken care of by the software engineer.
Difference in Control Over Where the Memory Is
Though managed code is typically more secure and is processed in a somewhat sandboxed, managed environment (the CLR with regards to the .Net Framework), the code is also limited due to that very reason. Software developers who program specific parameters into an application’s source code (an application that is to run within the .Net framework) detailing memory management, exception handling, security, etc. will essentially be unable to dictate those features to the CLR. The CLR will manage the code according to its needs, making managed code a somewhat inflexible system of code execution (compared to unmanaged code). At the same time, the interoperability, virtualizing nature of the .Net and JRE framework also means that the CLR system is typically slower than faster C/C++ code that is executed without the runtime checks, etc. that make the managed code system safe.
For example, the C language often requires programmers to use pointer variables, which allows developers to hold an address in memory that points to another piece of data (variable). In a managed code system – pointers are considered unsafe code. CLRs cannot usually run pointers, which must run outside of the managed code CLR system; specifically, C# pointers must be marked as unsafe code. In the context of the .Net framework, unsafe code loses the garbage collection features, while allowing for direct memory management. Pointers in .Net framework applications are often used for speed. However, using such programming constructs means that the full features of the .Net framework system are unable to accommodate their use.
Advantages of Using an Unmanaged Language
Using an unmanaged code system for application development gives developers much more control over their code. Software engineers can construct applications with lower level access and direct access to the hardware. Having less restrictions also means having complete control of the application, which allows experienced programmers to implement features that wouldn’t be allowed in a managed code system. It is often said that unmanaged code gives you more rope and it also gives you more rope to hang yourself with. That is, you don’t have many constraints with unmanaged code, and this makes it easier to do yourself harm (accidentally) as well. Below are some advantages associated with using an unmanaged code system:
- Lower level access: lower level programming languages allow engineers to use and essentially control the resources associated with the lower level (the hardware architecture). Due to the ability to determine detailed memory management processes, C is often used to program Operating Systems, as it can touch the lower level of the PC architecture.
- Direct access to the hardware: C (a statically typed, unmanaged language) excels at lower level programming and is often used for hardware access and in embedded systems due to its ability to allocate memory, create buffers, allocate the heap and stack statically, and carefully manage the limited memory typically characteristic of embedded systems – all of which is crucial in embedded programming. Outside of embedded programming, unmanaged languages such as C allow for greater access to the hardware, which allows for more efficient applications that – according to benchmarks – typically outperform managed code languages/applications.
- Less restrictions/Complete control over the app: As noted before, unmanaged code allows programmers to bypass parameters and restrictions that managed code frameworks (such as the CLR) dictate, such as restrictions on pointer usage and direct/manual memory management.
Advantages of Using a Managed Language
In a managed language system, memory buffer(s) are automatically checked by the runtime environment to ensure no buffer overflows occur. When using C# or Java, one must allow and use unsafe code for programs (that will cause a buffer overflow to occur) to compile. Thus it is difficult to produce a buffer overflow using a managed language system.
Managed languages also implement garbage collection, which is the automatic management of allocated memory resources via the framework. This will typically entail the collector deallocating memory for objects no longer in use to free up memory resources. Languages such as C lack garbage collection, and since garbage collection is often regarded as difficult and time-consuming, relying on the automatic collection of managed language systems is a very critical advantage in software engineering.
In addition to above, managed languages provide both run-time type checking and reference checking, both of which are tremendous advantages:
- Run-time Type checking (dynamic type checking): As opposed to static type checking – which is used at the time of compiling the source code – dynamic type checking occurs at run-time. While C# is statically typed (checked at compile time), managed language systems use dynamic type checking at run-time, which may cause a program to fail at run-time if type errors exist. This ensures that programs are developed properly. It is important to note that most languages use static and dynamic type checking for a thorough type checking system.
- Reference checking: references are values used in programming languages to point to a given piece of data (e.g. a variable) in memory at a physical address, allowing a program to access it. Checking to determine whether references correctly point to valid objects or are not duplicated (in the case of a reference equality check) ensures the seamless execution of the given program and all of its functions.
Disadvantages of Using Unmanaged Language
Being given full reins of an application’s code does remove certain limitations, while opening up the possibility for a myriad of bugs, including run-time errors, security bugs (e.g. buffer overflows), and issues associated with memory management. Even error and exception handling must be dealt with fully by the developer in an efficient way. Using managed code allows for quicker development of applications, without having to focus on certain complexities such as garbage collection and security. At the same time, using unmanaged code in a managed system requires the use of certain precautions associated with calling on the untrusted code, often using a complex permissions system and certain secure coding methods. That said, the increase in the number of possible variables and ways that a program can be developed creates an increase in the number of possible mechanisms that can go wrong.
Disadvantages of Using Managed Languages
Managed languages clearly show their use and advantages, while also having the primary disadvantage of being unable to allocate memory directly or access lower level functions of a PC’s architecture. For experienced programmers who like to code down to the “metal,” such a thing is not fully possible using managed languages. Everything from memory management, exception handling, to security, is largely outside of the control of the developer, leaving him/her without full reins of the application being developed.